Kevin Whitaker
Kevin Whitaker

Reputation: 13435

ActiveRecord repeating included associations in a query?

In my app, I have three models: Markets, Deals, and Users. Relationships are pretty straightforward:

class Market
  has_many :users
  has_many :deals
end

class User
  belongs_to :market
end

class Deal
  belongs_to :market
end

Now, in order to more easily query some of those relationships, the Market model has some methods attached to it:

class Market
  def revenue_by_date(date)
    deal = self.deals.find(:all, :select => 'id, purchased, price', :conditions => ["start_time =?", date])[0]
    i = 0
    if deal && deal.isMade?
      i = deal.purchased * deal.price
    end
    return i
  end

  def users_for_market
    return self.users.count
  end
end

So, in my controller, I need to collect data pertaining to all of the markets together, and then I need to drill down in various places. So I have a query that looks like this:

markets = Market.find(:all, :order => :name, :include => [:users, :deals])

This runs the two include queries as expected, but later in my code where I do something like this:

markets.each do |m|
  m.users_for_market
  m.revenue_by_date(date_var)
end

it runs the individual queries in those model methods. I thought that the :include was supposed to supplant that?

What can I do to cut down on the number of queries I'm running?

Upvotes: 1

Views: 154

Answers (1)

Jaime Bellmyer
Jaime Bellmyer

Reputation: 23317

:include is awesome, but if you call new database queries down the line, it won't stop you. You can reduce the DB hits though, by changing your Market methods:

class Market
  def revenue_by_date(date)
    deal = self.deals.select{|d| d.start_time == date}.first

    i = 0
    if deal && deal.isMade?
      i = deal.purchased * deal.price
    end
    return i
  end

  def users_for_market
    return self.users.size
  end
end

Let's work backward - in users_for_market, the count method does a db lookup, the size method just checks the array. In revenue_by_date, I replaced your database query with a ruby select method, which iterates over the items and only returns the ones where the select block equates to "true".

Rails won't stop you from making more database queries, but you can easily use ruby code to work with what you've already loaded. I hope this helps!

Upvotes: 1

Related Questions