【问题标题】:rails 4 eager loading heavy associationrails 4 急切加载重关联
【发布时间】:2014-05-19 07:35:00
【问题描述】:

我在 Rails 模型之间建立了关联。

描述product属性的模型共有三种:

Property正在关联模型,每个属性都有一个名称和值。

class Property < AR::Base
  belongs_to :product
  belongs_to :property_name
  belongs_to :property_value

class PropertyName < AR::Base
  has_many :properties
  validates :name, presence: true, uniqueness: true

class PropertyValue < AR::Base
  has_many :properties
  validates :value, presence: true, uniqueness: true

通过thinking-sphinx 搜索后,我得到了方面 - property_values id & property_names id 集合。

使用该结果,然后我尝试查找products 的当前列表的所有属性(以继续过滤这些搜索结果)。

在我使用的控制器中:

@property_names = PropertyName
  .where(id: property_name_ids)
  .includes(:property_values).where('property_values.id IN (?)', property_value_ids)

我的看法:

- @property_names.each do |property_name|
  h4 = property_name.name
  - property_name.property_values.pluck(:value).uniq.each do |property_value|
    = check_box_tag ...
    = label_tag ...

因此,急切加载不起作用。 Rails 为数据库生成了很多 (n+1) 个查询。怎么了?为什么包含不起作用?

【问题讨论】:

  • 与您的问题无关。您可以重新考虑您的codePropertyNamePropertyValue 看起来很像 Property 中的 attributes 而不是 separate models。对我来说这看起来很不合适。
  • @Pavan 是的,它可以是一个字符串。但是thinking-sphinx需要它是一个模型关联=)
  • 我对您的问题进行了大量编辑,以试图澄清内容。我仍然很难准确理解你在最后一段中要表达的意思。你能花点时间为我们更新一下吗?我认为这会帮助您更快地得到答案。
  • 好的。请稍等

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord


【解决方案1】:

由我解决。

首先,在property_names处添加关联has_many :property_values, -&gt; { uniq }, through: :properties

之后,我使用这个查询:

  @property_names = PropertyName.where(id: property_name_ids).where.not(name: PropertyName.description)
    .includes(:property_values).where(property_values: { id: property_value_ids }).order('property_values.value')

一切正常!

【讨论】:

  • .where(property_values: { id: property_value_ids }) 这救了我的命。在我的情况下,条件总是应用于错误的模型。
【解决方案2】:

您似乎包含了一个未定义的关联,因为PropertyName 没有定义“property_values”关系。

您可能想要执行以下操作:

 PropertyName.includes(properties: :property_value)

【讨论】:

  • 不,它不起作用。或者,也许,我需要在视图中指定一些东西?
  • 不,在视图中无需指定任何额外内容。除非您可以更改遍历记录和准备集合的方式。在这种情况下,我会尝试将查询更改为数据库,因此它将返回唯一的 property_values,按 property_names 分组。这样,您的集合将更像您在视图层中使用它所做的事情,并且您肯定会摆脱 N+1 个查询。
  • 我在结果中得到了那个查询:@property_names = PropertyName.includes(properties: :property_value).where(property_values: { id: @property_value_ids }).where(id: property_name_ids).where.not(name: propertyName.description).references(:properties) 在视图中我写了- @property_names.each do |p_n| ... p_n.property_values.each do ... 并得到了 n+1 查询!我怎样才能避免这种情况?
  • 是的,我可以在您的原始帖子中看到这一点。我的建议是将查询更改为数据库,因此它将返回唯一的 property_values,按 property_names 分组。 PropertyValue.select('distinct property_values.*').joins('your property names').where('your conditions').group('properties.name') 的一些东西。然后迭代组,从中取出名称,并通过关联的组内容构建您的复选框。
  • 我合理地发现了一个错误:ERROR: column properties.name does not exist,因为properties 表中没有name 列。其他问题:joins('your property names') 是什么意思?我需要传递一个获取 property_names 的变量还是只使用 joins(:property_names)??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多