Railsアソシエーションが熱心にロードされているかどうかを判断する方法を知っている人はいますか?
私の状況:結果セットがあり、関連付けの1つが積極的に読み込まれる場合とそうでない場合があります。積極的に読み込まれていない場合は、ActiveRecordの検索を使用して関連付けを検索します。熱心にロードされている場合は、検出を使用します。
たとえば、アイテムモデルにshipping_infoオブジェクトの「has_many」配列があるとします。次に:
アイテムを積極的にロードする場合、最も効率的なロードは次のとおりです。
item.shipping_infos.detect { |si| si.region == "United States" }
アイテムが積極的に読み込まれていない場合、最も効率的な読み込みは次のとおりです。
item.shipping_infos.where(region: "United States").first
しかし、それが積極的にロードされているかどうかを知らない限り、レコードを効率的に取得するために呼び出すコードがわかりません。熱心に読み込まれなかったときに最初の方法を使用した場合、必要以上のDBレコードを検索する必要があります。また、2番目の方法を積極的にロードしたときに使用した場合、積極的にロードされたオブジェクトは無視されます。
item.shipping_infos.loaded?
教えてくれます。
ただし、このパスは狂気につながる...をテストするコードを書く前にloaded?
#detect
および#find
、このインスタンス本当にが重要であることを確認してください。
これがアプリの最も遅い処理ではない場合、コードパスを追加すると、不必要に複雑になります。わずかなデータベースの労力を浪費する可能性があるからといって、それを修正する必要があるという意味ではありません。測定可能な方法ではおそらく問題ではありません。
レコードで.association(name).loaded?
を使用します。
Rails <3.1の場合、loaded_foo?
。
(Rails 3.1。参照: https://github.com/Rails/rails/issues/472 なので非推奨です。)
積極的に読み込まれた関連付けのリストを提供するitem.association_cache.keysを使用することをお勧めします。つまり、item.association_cache.keys.include? :name_of_association
Loaded _foo?で単一のアソシエーションがロードされているかどうかを検出できます。たとえば、shipping_infoがbelongs_to関連付けだった場合、item.loaded_shipping_info? eager-loadedの場合はtrueを返します。奇妙なことに、(Rails 2.3.10とにかく)ロードされていない場合、(falseではなく)nilを返すようです。
この問題の解決策はfoo.association(:bla).loaded?
である必要がありますが、正しく機能しません。関連付けを確認してダーティとしてマークします。
class Foo; has_one :bla, :autosave => true end
foo.association(:bla).loaded? #=> false
foo.save # saves foo and fires select * from bla
そこで、ActiveRecordに次の拡張機能を追加しました。
module ActiveRecord
class Base
def association_loaded?(name)
association_instance_get(name).present?
end
end
end
そして今:
class Foo; has_one :bla, :autosave => true end
foo.association_loaded?(:bla) #=> false
foo.save # saves foo
Bullet gem。 をご覧ください。これにより、イーガーロードを使用する必要がある場合と使用しない場合がわかります。
association_cached?
が適切かもしれません:
item.association_cached?(:shipping_infos)