I've written about Ransack before, because it's a handy, little gem for searching quickly through both models and their relationships. But you may be surprised to know it's deceptively easy to create N+1 queries using Ransack! The good news is, it's just as easy to fix.
To review basic Ransack use, let's say you have a model
Service, which has properties for
description. If you wanted to search both of those properties, you'd set up your view with something like this:
<%= search_form_for @q do |f| %> <%= f.label :name_cont %> <%= f.search_field :name_description_cont %> <% end %>
And your controller would be:
def index @q = Service.ransack(params[:q]) @services = @q.result(distinct: true) end
Pretty basic stuff, right? But what if you have another model associated with Services? For example, let's say you have a
Provider model with
address properties, and each
Now, you want to search the
description properties for
Service, but you also want to include the
name property as well. How do you do that?
Ransack provides an easy approach. You can change your view to:
<%= search_form_for @q do |f| %> <%= f.label :name_cont %> <%= f.search_field :name_description_provider_name_cont %> <% end %>
Yikes! That's not what we want at all!
Those familiar with rails will know the dreaded N+1 Problem, but will also likely know we can usually solve it with eager loading and using
includes(:model_name) . But where do we put it? Easy, in the Controller of course!
def index @q = Service.includes(:provider).ransack(params[:q]) @services = @q.result(distinct: true) end
Running our search again:
(Please note that in my examples, I also have Sub Categories loading for another part of my view)
This isn't a difficult problem to solve, but many may not be aware that using Ransack with associated models can end up creating this N+1 problems.
Good luck, and happy coding!