1

我想知道我们是否可以在模型级别急切加载:

# country.rb
class Country < ActiveRecord::Base
  has_many :country_days

  def country_highlights
    country_days.map { |country_day| country_day.shops }.flatten.uniq.map { |shop| shop.name }.join(", ")
  end
end

# country_day.rb
class CountryDay < ActiveRecord::Base
  belongs_to :country
  has_many :country_day_shops
  has_many :shops, :through => :country_day_shops
end

# shop.rb
class Shop < ActiveRecord::Base    
end

大多数时候,由于某些多态关联,很难.includes在控制器中使用。无论如何,我是否可以country_highlights在模型级别急切加载该方法,这样我就不必.includes在控制器中添加?

4

2 回答 2

2

您不能从模型实例“急切加载” country_days,但您当然可以使用has_many through:. 您也可以跳过额外的地图。

# country.rb
class Country < ActiveRecord::Base
  has_many :country_days
  has_many :country_day_shops, through: :country_days  #EDIT: You may have to add this relationship
  has_many :shops, through: :country_day_shops #And change this one to use the new relationship above.

  def country_highlights
    shops.distinct_names.join(", ")
  end
end

# country_day.rb
class CountryDay < ActiveRecord::Base
  belongs_to :country
  has_many :country_day_shops
  has_many :shops, :through => :country_day_shops
end

# shop.rb
class Shop < ActiveRecord::Base
  def self.distinct_names
    pluck("DISTINCT shops.name")  #Edit 2: You may need this instead of 'DISTINCT name' if you get an ambiguous column name error.
  end
end

has_many through:使用 aJOIN加载关联商店记录,实际上是预先加载它们,而不是加载所有 country_day 记录,然后为每个 country_day 记录加载关联商店。

pluck("DISTINCT name")将返回数据库中所有唯一商店名称的数组,使用数据库执行 a SELECT DISTINCT,因此它不会返回重复记录,并且pluck当您只需要字符串时将避免加载 ActiveRecord 实例name

于 2013-04-21T19:23:49.077 回答
1

编辑:先阅读评论

您可以缓存最终结果(在您的情况下是连接的字符串或文本记录),因此您不必加载多个级别的记录来构建此结果。

1) 添加一个country_highlights文本列(结果可能超出字符串列限制)

2) 使用回调将模型缓存country_highlights在模型中,例如在每次保存之前。

class Country < ActiveRecord::Base  
  has_many :country_days

  before_save :cache_country_highlights

  private

  def cache_country_highlights
    self.country_highlights = country_days.flat_map(&:shops).uniq.map(&:name).join(", ")
  end
end

保存记录时缓存计算会产生一点开销,但只需要加载一个而不是三个模型记录来显示应该会大大加快控制器操作的速度,这是值得的。

于 2013-04-21T18:50:31.340 回答