Filtering models in ActionController
Today, I encountered a challenge of listing models and filtering them with some request parameters in ActionController of Rails. Initially, I thought about chaining the where
clauses of ActiveRecord in the controller.
class EventsController
def index
@events = Event.where(nil)
@events = @events.where(request_id: params[:request_id]) if params[:request_id].present?
@events = @events.where('created_at > ?', params[:start_date]) if params[:start_date].present?
@events
end
end
But this looks a bit tedious with all the chaining queries and if
check. So with the pubic_send
method in Ruby, I could do something better with a loop and custom method. To do that, I used scope
in the model:
class Event
scope :filter_by_request_id, ->(request_id) { where(request_id: request_id }
scope :filter_by_start_date, ->(start_date) { where('created_at > ?', start_date }
endclass EventsController
def index
@events = Event.where(nil) filtering_params(params).each do |key, value|
@events = @events.public_send("filter_by_#{key}") if value.present?
end
@events
end def filtering_params(params)
params.slice(:request_id, :start_date)
end
end
This looks better and the thing is I will need to create this code segment for each model and controller which needs filtering. So a even reusable solution is to use concern
of ActiveSupport in model and put the logic in it.
module Filterable
extend ActiveSupport::Concern def ClassMethods
def filter(params)
results = where(nil) params.each do |key, value|
results = results.public_send("filter_by_#{key}") if value.present?
end results
end
endclass Event
include Filterable scope :filter_by_request_id, ->(request_id) { where(request_id: request_id }
scope :filter_by_start_date, ->(start_date) { where('created_at > ?', start_date }
end
So in this way, in the controller, I can just use this class method defined in the concern and used in the other controllers too.
class EventsController
def index
@events = Event.filter(params.slice(:request_id, :start_date))
end
end
Thanks for the reading and this is it.
All the credit to the original author:
https://www.justinweiss.com/articles/search-and-filter-rails-models-without-bloating-your-controller/