2
\$\begingroup\$

I have a has_many through relationship between my cities and travels that looks like this:

class Travel < ActiveRecord::Base
  has_many :cities, through: :destinations
end
class City < ActiveRecord::Base
  has_many :travels, through: :destinations
end

And on my Travel controller I have a method to join all its cities names:

  def city_names
    self.cities.map { |e| e.name }.join(', ')
  end

I installed the bullet gem and it tells me that this is a n+1 query and suggests that I add the includes method on the query, but as far as I can tell this method will only work if I call it directly on the Travel class.

\$\endgroup\$
3
  • \$\begingroup\$ Don't use the meaningless variable e; use something like city instead \$\endgroup\$ Mar 19, 2015 at 1:04
  • \$\begingroup\$ Did you try calling includes on self in the city_names method? \$\endgroup\$ Mar 19, 2015 at 1:41
  • \$\begingroup\$ even better, just call map with (&:name) instead of a block \$\endgroup\$ May 29, 2015 at 13:05

1 Answer 1

2
\$\begingroup\$

You can use includes on any activerecord relation.

Judging by your message about having N+1 queries I suspect you are calling city_names somewhere in a loop. then the correct placement of the includes is the place where you select the elements to loop past.

I'm guessing it is for a view or something so i write some example code for .html.erb.

In controller:

@travels = Travels.all.includes(destinations: :cities)

In view:

<% @travels.each do |travel| %>
  ... Some code displaying travel info
  <%= travel.city_names %>
  ... More code displaying travel info
<% end %>

And a suggestion in line with what Mark Thomas wrote as a comment. You can refactor you city_names method for more readable code, either according to his suggestion or like this:

def city_names
  self.cities.map(&:name).join(', ')
end
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.