I'm trying to extend the functionality of my serverside datatable. I pass some extra filters to my controller / datatable, which I use to filter results. Currently in my model I am testing whether the params are present or not before applying my scopes, but I'm not convinced this is the best way since I will have a lot of if/else scenario's when my list of filters grows. How can I do this the 'rails way'?
if params[:store_id].present? && params[:status].present?
Order.store(params[:store_id]).status(params[:status])
elsif params[:store_id].present? && !params[:status].present?
Order.store(params[:store_id])
elsif !params[:store_id].present? && params[:status].present?
Order.status(params[:status])
else
Order.joins(:store).all
end
ANSWER: Combined the answers into this working code:
query = Order.all
query = query.store(params[:store_id]) if params[:store_id].present?
query = query.status(params[:status]) if params[:status].present?
query.includes(:store)
You could do it like this:
query = Order
query = query.store(params[:store_id]) if params[:store_id].present?
query = query.status(params[:status]) if params[:status].present?
query = Order.joins(:store) if query == Order
Alternatively, you could also just restructure the status
and store
scopes to include the condition inside:
scope :by_status, -> status { where(status: status) if status.present? }
Then you can do this instead:
query = Order.store(params[:store_id]).by_status(params[:status])
query = Order.joins(:store) unless (params.keys & [:status, :store_id]).present?
Since relations are chainable, it's often helpful to "build up" your search query. The exact pattern for doing that varies widely, and I'd caution against over-engineering anything, but using plain-old Ruby objects (POROs) to build up a query is common in most of the large Rails codebases I've worked in. In your case, you could probably get away with just simplifying your logic like so:
relation = Order.join(:store)
if params[:store_id]
relation = relation.store(params[:store_id])
end
if params[:status]
relation = relation.status(params[:status])
end
@orders = relation.all
Rails even provides ways to "undo" logic that has been chained previously, in case your needs get particularly complex.
The top answer above worked for me. Here is an example of its' real-life implementation:
lessons = Lesson.joins(:member, :office, :group)
if @member.present?
lessons = lessons.where(member_id: @member)
end
if @office.present?
lessons = lessons.where(office_id: @office)
end
if @group.present?
lessons = lessons.where(group_id: @group)
end
@lessons = lessons.all
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With