在大型 Rails 应用程序中,我注意到我们有一段代码可以生成大型 ActiveRecord::Relation
。它在 .joins()
调用中使用自定义 SQL 片段——类似这样:
def foos
Foo.
joins("INNER JOIN bars ON foos.bar_id = bars.id").
joins("INNER JOIN baz ON bars.baz_id = baz.id").
where(<some condition on bars>)
end
(请注意,JOIN
比本例中所示的更复杂;否则我显然只会执行 Foo.joins(bar: :baz)
。 ) 现在,在一些使用 ActiveRecord::Relation
的地方,这很好。但在其他情况下,我们希望在 Foo
结果集上预先加载 bars
关联。
有没有办法做这样的事情:
def scope_with_bars_eager_loaded
foos.eager_load(:bars, using_existing_join_in_query: true)
end
我能想到的最接近的是:
def array_with_bars_eager_loaded
foos.pluck(<fields we need>).map do |fields|
bar = Bar.new(<get bar data from fields>)
# This of course doesn't behave as well as a Foo
# that we've loaded normally in regards to callbacks,
# fields we didn't SELECT, etc. But it's probably
# fine enough for this use-case (we're using this
# data to render a page).
Foo.new(<get foo data from fields>, bar: bar)
end
end
这要复杂得多,而且也没有给我们带来成为 ActiveRecord::Relation
的好处。如有任何帮助,我们将不胜感激!
--
注意:
任何避免 Rails 默认行为“加载数据库中的每一列,有时在一个查询中多次”的建议都特别受欢迎(这就是为什么我使用 .pluck
而不是 的原因。 select
,因为 .select
构造的查询会加载 Foo
中的所有内容,即使您明确告诉它不要这样做)。示例:Foo.includes(:bar).where(bars: { condition: true }).select(:id)
选择 foos
中的每一列,并选择 foos.id
两次。
最佳答案
好吧,我最终重组了我的 foos
方法,这样它就可以在那里简单地执行 includes
。仍然对所有字段都被 SELECT
编辑感到非常满意,但我想这就是您使用 ActiveRecord
而不是 Sequel
之类的东西所得到的。
关于ruby-on-rails - 使用 INNER JOIN 的 Rails ActiveRecord eager_load,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45723610/