2012-01-07 45 views
2

(使用Rails 3.1.3)複雜查詢,使用:includes和:同時連接?

我有一個管理產品的應用程序。我從幾個經銷商那裏進口產品,並且他們的產品類別都有所不同。正因爲如此,我有經銷商類別映射到我自己的子類別。

分類

小類(belongs_to的範疇)

Resellercategories(belongs_to的子類別)

產品(belongs_to的Resellercategory)

你可以看到模型,以及如何關係定義如下: http://snipt.net/Linuus/category-and-subcategory?key=38ba590408ac4233927a06046eeca30d

在我的網站I想要顯示類別及其子類別,很簡單。

如果用戶僅針對「女性」產品過濾產品,則還要過濾類別和子類別,以便僅顯示具有「女性」產品的類別和子類別。性別存儲在產品中。

那麼,我該怎麼做呢?

我試圖創建一個這樣的查詢: http://snipt.net/Linuus/categories-1/?key=2d5d54fd573f0afe60eaa3c47a23fd4d 哪(我認爲)過濾正確的類別。然而,當我這樣做:

@menu_categories.each do |c| 
    c.subcategories.each do |sc| 
     # do something... 
    end 
end 

它仍然會查詢所有的子類別是否他們有女性產品。所以,我在Ruby on Rails的Google Group上得到了一個建議,使用.includes()急切地加載子類別。所以,這樣的事情:

Category.includes(:subcategories) 
     .joins("INNER JOIN resellercategories AS r ON subcategories.id = r.subcategory_id") 
     .joins("INNER JOIN products AS p ON r.id = p.resellercategory_id") 
     .group("categories.id") 
     .order("categories.name ASC") 
     .where("p.gender = 'unisex' OR p.gender = 'female'") 
     .where("subcategories.id > 0") # Dummy to trigger eager loading 

然而,混合.includes當()和.joins()中包含似乎不能急於加載任何東西。因此拋出以下錯誤:

ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: subcategories.id: 
SELECT "categories".* FROM "categories" 
INNER JOIN resellercategories AS r ON subcategories.id = r.subcategory_id 
INNER JOIN products AS p ON r.id = p.resellercategory_id 
WHERE (p.gender = 'unisex' OR p.gender = 'female') 
GROUP BY categories.id 
ORDER BY categories.name ASC 

此行爲是否預期?這是一個錯誤嗎? 我是想以正確的方式做到這一點,還是有更好的方法來做到這一點?

任何幫助非常感謝。

(該上RoR的谷歌小組討論:https://groups.google.com/forum/?pli=1#!topic/rubyonrails-talk/UkCF7jbehHk

解決方案: 好了,所以該解決方案是使用eager_load(),而不是包括()。我也不得不刪除組() 這似乎爲我工作:

Category.eager_load(:subcategories) 
     .joins("INNER JOIN resellercategories AS r ON subcategories.id = r.subcategory_id") 
     .joins("INNER JOIN products AS p ON r.id = p.resellercategory_id") 
     .order("categories.name ASC") 
     .where("p.gender = 'unisex' OR p.gender = 'female'") 
+0

自定義'.joins'優先或類似的東西愚蠢。我會看看我能否想出更好的方法。 – Azolo 2012-01-07 17:19:52

回答

1

Rails不總是使用連接以實現包括。您也可以通過執行eager_load而不是includes來強制執行此操作。

+0

謝謝! eager_load()似乎有訣竅。我也必須刪除組()。將使用正確的信息更新我的原始帖子。 – Linus 2012-01-07 18:00:25

1

該AR鏈看起來更清潔。

Category.joins({:subcategories => 
       {:resellercategories => 
       :products}}) 
     .includes(:subcategories) 
     .where('products.gender = unisex OR 
       products.gender = ?', gender) 

但我不認爲它會解決你的原始問題獲得所有subcategories。爲了解決這個問題,你實際上必須查詢關聯。

@menu_categories.each do |c| 
    c.subcategories.joins({:resellercategories => 
          :products}}) 
        .where('products.gender = unisex OR 
          products.gender = ?', gender) 
        .each do |sc| 
     # do something... 
    end 
end