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 name and 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 name and address properties, and each Provider has_many Services.
Now, you want to search the name and description properties for Service, but you also want to include the Providers 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 %>
Things are working smoothly.  But hold on, let's look at the SQL query that runs when we try to search for something:

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!
 
 
              

 
    
Top comments (6)
Super helpful little post
Any reasons not to use relations and joins?
Sorry for the late reply!
I'm not sure I understand your question. In the example,
ServiceandProviderare related, and I suppose you could do something like,perhaps? But I have not tested it. Moreover, this would bypass any resource authorization libraries (like Cancan)
Awesome reminder! Thanks!
Hi @husteadrobert, small question what if you search with multiple models ? each model has diff relationships
doesn't using includes eagerload or preload the association: wouldn't it be more efficient to simply use a joins method if in fact we are only seeking Service records?