のJOIN INNERとeager_load、私たちは大きなActiveRecord::Relation
を生成するコードの一部を持っていることに気付きました。これは、このような.joins()
呼び出し、何かにカスタムSQLスニペットを使用しています。RailsのActiveRecordのが大のRailsアプリで
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
が使用されている場所のうち、それは問題ありません。しかし、他のものでは、結果セットにbars
の関連付けをeager-loadedしたいと考えています。
すると、このような何かをする方法はあります:
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
のメリットを与えてください。ここのお手伝いをいただければ幸いです!
-
注:
『1つのクエリでの負荷、データベース内のすべての列、時には複数回』のRailsのデフォルトの動作を回避するための任意の提案、特に私が代わりに.pluck
を使用理由です(感謝しています.select
は、明示的ではないにそれを教えても、Foo
ですべてをロードするクエリを構築するよう.select
、)の。例:Foo.includes(:bar).where(bars: { condition: true }).select(:id)
はfoos
のすべての列を選択し、二回foos.id
選択します。
私はあなたがそれを使用している方法に多少依存します。 'Foo.new(hash_of_stuff_i_plucked_from_the_db)'を実行すると、レコードは新しいレコードのように動作し、DBからフェッチされません。これは、コールバックになると予期しない動作が発生し、たとえばフォームに渡すとどうなりますか。 – max
'.joins'が' LEFT INNER JOIN'を作成しているので 'joins(" INNER JOIN bar foos.bar_id = bars.id ")'というコードはちょっと変わっています。 :バー) '。 '.joins'と' .eager_load'の主な違いは '.joins'は' INNER'と '.eager_load''OUTER'を使います。また – max
.pluck'セレクトリターン(アレイの)配列を返し.pluck' 'のActiveRecord :: Relation'と'ことである.select'と ''の差。あなたは '.select'を使って、ARにぴったりな列を正確に伝えることができます。 '@foo = Foo.select( 'foos.id、foos.baz、bars.id、bars.baz').joins(:bars)'は、例えば、指定された列だけをロードします。 – max