在一个大的Rails应用程序中,我注意到我们有一段代码产生一个大的ActiveRecord::Relation
。它使用自定义的SQL代码片段在.joins()
通话,这样的事情:Rails的ActiveRecord eager_load与INNER JOIN
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
s为比这个例子中,如图比较复杂,否则我明明只是做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
两次。
我在某种程度上取决于你如何使用它。如果你做了'Foo.new(hash_of_stuff_i_plucked_from_the_db)',那么记录的行为就像是一条新记录,而不是从数据库中取出。当涉及到回调时,这会给您带来意想不到的行为,当您将其传递给表单时会发生什么情况。 – max
由于'.joins'创建了一个'LEFT INNER JOIN'并且你可以将它写成'.joins(),所以代码'joins(“INNER JOIN bars on foos.bar_id = bars.id”)' :条)'。 '.joins'和'.eager_load'之间的主要区别是'.joins'使用'INNER'和'.eager_load''OUTER'。 – max
'.select'和'.pluck'之间的区别在于select返回一个'ActiveRecord :: Relation','.pluck'返回一个数组(数组)。您可以使用'.select'来告诉AR到底要采集哪些列。例如'@foo = Foo.select('foos.id,foos.baz,bars.id,bars.baz')。joins(:bars)'只会加载名为的列。 – max