0

I have been trying to refactor this code to reduce the db calls by possibly using "includes". I would like to replace the three nested loops in the view. Tried various options but got stuck... I'm still getting familiar with active record querying.

How can I make this more efficient with less queries? Is using includes the best option? If so, how do I access the various fields through my HABTM relationships?

Thanks.

Models:

class Category < ActiveRecord::Base
  has_many :pub_types
end

class PubType < ActiveRecord::Base
  belongs_to :category
  has_and_belongs_to_many :issues
end

class Issue < ActiveRecord::Base
  has_and_belongs_to_many :pub_types
  has_many :images, :dependent => :destroy
end

Controller:

def home
  @categories = Category.all
  @issues_and_pubs = Issue.joins(:pub_types).uniq
end

View:

<% @categories.each do |category| %>
    <%= category.name %>
        <% @issues_and_pubs.where(:pub_types => {:category_id => ["#{category.id}"]}).each do |issue| %>
            <% issue.images.each do |img| %>
                <% if img.featured == true %>
                    <%= cl_image_tag img.image, :width => 295, :height => 155, :alt => img.name, :crop => :fill %>
                    <%= link_to issue.name, issue %>
                <% end %>
            <% end %>
        <%= issue.issue_date.try(:strftime, "%B %d, %Y") %>
    <%= issue.pub_types.map(&:name).join(", ") %>
    <% end %> 
<% end %> 
Brad Werth
  • 17,411
  • 10
  • 63
  • 88
NanoCat
  • 559
  • 7
  • 12

1 Answers1

0

Try this instead.

Add this to Category:

has_many :issues, through: :pub_types

Controller:

@categories = Category.includes(:issues => :images)

View:

@categories.each do |category|
  category.issues.each do |issue|
    issue.images.each do |image|
    issue.pub_types # might still result in N+1, haven't tested

On the note above about N+1 on pub_types, I have had occasions where I've eager loaded associations, but Rails has not taken them into account when calling from children to parents. One approach I've used in the past is to be explicit with the references:

Category.includes(:issues => [:pub_types, :images])

Without the has_many through:, this would look rightly peculiar:

Category.includes(:pub_types => [:issues => [:pub_types, :images]])

Damien Roche
  • 13,189
  • 18
  • 68
  • 96
  • Much improved! I did not know I could assign a HMT association with my current HABTM setup -Thanks for that. The only issue I am having is the results are repeated based on the number of pub_types. So when four pub_types are in the DB the issue.name, images, etc are repeated four times. Two pub_types, two results etc... Not sure what's causing this behavior. Additionally, I went with eager loading on the associations because of N+1 on pub_types was taking place -good call. – NanoCat Aug 16 '14 at 01:38
  • Still not entirely sure why I am getting duplicate results. However, I "resolved it" using `category.issue.uniq.each do |issue|` – NanoCat Aug 16 '14 at 15:18