2009-09-03 55 views
38

有沒有人知道一種方式來確定Rails關聯是否已被加載?如何確定Rails協會是否急於加載?

我的情況:我有一個結果集有時其中一個關聯是急切加載,有時不是。如果它不是急切加載的,那麼我想使用ActiveRecord的查找來查找關聯。如果它急於加載,我想使用檢測。

例如,假設我的項目模型中有一個「has_many」的shipping_info對象數組。然後:

如果項目急於裝,最有效載荷爲:

item.shipping_infos.detect { |si| si.region == "United States" } 

如果產品沒有急於裝,最有效載荷:

item.shipping_infos.where(region: "United States").first 

但是,除非我知道它是否是急於加載,我不知道要調用哪個代碼來有效地獲取記錄。如果我使用第一種方法時,它不是急於加載,那麼我必須查找更多的數據庫記錄。如果我在使用第二種方法時被加載,那麼我的加載對象將被忽略。

回答

41

item.shipping_infos.loaded?會告訴你。

我得說,雖然:這條路通向瘋狂...編寫測試loaded?#detect#find之間做出選擇的代碼之前,要確保這種情況下真的事項,相對於其他一切事情。

如果這不是應用程序最慢的事情,那麼添加額外的代碼路徑會增加不必要的複雜性。僅僅因爲你可能浪費了一點數據庫的努力並不意味着你需要修復它 - 這可能不會以任何可測量的方式。

+0

謝謝布萊恩。我明白你來自哪裏。不過,這個特殊的代碼碰巧在我們整個應用程序中被最頻繁地稱爲部分代碼,所以即使在幾微秒的時間內削減也會產生可測量的差異。我會給#加載?一試。 – wbharding 2009-09-04 06:49:17

+9

這隻適用於has_many關聯!在belongs_to的情況下,這個調用實際上會加載另一個對象(所以它總會是真的) – reto 2009-10-16 12:02:21

2

看看Bullet gem.。這會告訴你什麼時候你應該和不應該使用急切的加載。

+0

儘管我已經做了很少的其他數據庫優化,但是Bullet已經證明非常有用。至少它在控制檯輸出中刪除了一些不必要的行。 ;) – lime 2013-07-15 14:47:45

+0

子彈插件鏈接已死亡。 – 2015-08-21 21:20:33

3

您可以檢測單個關聯是否已經加載了loaded_ foo?例如,如果shipping_info是belongs_to關聯,那麼item.loaded_shipping_info?當它被加載時會返回true。奇怪的是,它似乎在沒有被加載時返回零(而不是錯誤)(無論如何,Rails 2.3.10)。

+3

這已在Rails 3.1中刪除:https://github.com/rails/rails/issues/472 – Forrest 2012-03-27 00:52:32

2

這個問題的解決應該是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 
+0

你應該仔細檢查,這仍然是一個問題,並更新答案,以適用於適當的Rails版本。我無法複製。 – 2015-08-21 21:26:18

+0

Rails 4.2.6仍然存在問題。不確定Rails 5是否擁有它。 – Omnilord 2016-08-13 15:29:49

+0

將它標記爲髒的後果是什麼?只需一個額外的選擇語句?還是有更多的傷害呢? – lulalala 2016-10-25 02:59:47

19

我建議使用item.association_ cache.keys將提供預先加載的關聯列表。所以你item.association_cache.keys.include?:name_of_association

+1

完美的解決方案。 Dabogert你是國王:) – Benj 2014-01-30 23:41:27

+0

哇,不能相信我一直想念這個。這適用於未加載關聯的情況,但存在內存緩存(例如,當您使用關聯構建對象時)。 – 2014-08-04 13:27:53