2013-03-21 82 views
4

我有以下型號渴望負荷協會:活動記錄:與參數

class Rating < ActiveRecord::Base 
    belongs_to :item 
    belongs_to :user 
end 

class Item < ActiveRecord::Base 
    has_many :ratings 
end 

我想獲取的所有項目,並通過特定的用戶所做的收視率,以顯示當前用戶的等級(如果存在的話! )每個項目旁邊。

我試過......

Item.includes(:ratings).where('ratings.user_id = ?', user_id) 

...但是,這不給我,沒有收視率的項目。

我首先想到的是用自變量的關聯的has_many,然後再傳遞該參數與包括方法。但這似乎並不存在。

如何獲得的所有帖子,並渴望加載關聯過濾上沒有做N + 1個查詢或加載所有實體到內存的參數?

+0

檢查此鏈接。 http://stackoverflow.com/questions/4197418/rails-3-eager-loading-with-conditions – 2013-03-21 08:57:42

+0

請包括用戶模型 – gabrielhilal 2013-03-21 09:08:23

+1

@AbibullahRahamathulah這個問題是關於靜態參數(has_many條件),而不是動態的 – thejaz 2013-03-21 09:16:15

回答

5

步驟1

充分利用current_user在模型層訪問的(一個技術這裏概述:https://stackoverflow.com/a/2513456/163203

步驟2

添加的關聯與在運行時,就會執行這個的條件。

軌道2

class Item < ActiveRecord::Base 
    has_many :ratings 
    has_many :current_user_ratings, 
      :class_name => "Rating", 
      :conditions => 'ratings.user_id = #{User.current_user.try(:id)}' 
end 

導軌3。1及以上

步驟3

Item.includes(:current_user_ratings) 
+1

工作完美!小記:您鏈接到的步驟1中的答案不會採取預防措施,即線程變量不會在請求之間共享。我使用gem request_store來簡化存儲當前用戶並確保它不泄漏。 – thejaz 2013-04-23 20:18:09

+0

它看起來像'thin'和'puma'服務器有問題。順便說一句,該寶石使用'Thread.current'商店,他們在通話後清除它。 – 2013-04-23 23:36:52

+0

我已經解決了步驟1中建議的解決方案中的線程泄漏問題。 – 2013-04-23 23:44:07

0

它看起來像你基本上建模一個has_many :through關係:項目has_and_belongs_to_many用戶和評級是聯接模型。您可以在Rails Guide to Active Record Associations中閱讀關於:through關係。

如果是這樣的話,我會建議使用has_many :through如下構建模型的關係:

class Rating < ActiveRecord::Base 
    attr_accessible :item_id, :user_id 
    belongs_to :item 
    belongs_to :user 
end 

class User < ActiveRecord::Base 
    has_many :ratings 
    has_many :rated_items, :through => :ratings 
end 

class Item < ActiveRecord::Base 
    has_many :ratings 
    has_many :rated_by_users, :through => :ratings, :source => :user 
end 

然後,說你有在DB以下記錄:

$ sqlite3 db/development.sqlite3 'SELECT * FROM items'; 
1|2013-03-22 03:21:31.264545|2013-03-22 03:21:31.264545 
2|2013-03-22 03:24:01.703418|2013-03-22 03:24:01.703418 

$ sqlite3 db/development.sqlite3 'SELECT * FROM users'; 
1|2013-03-22 03:21:28.029502|2013-03-22 03:21:28.029502 

$ sqlite3 db/development.sqlite3 'SELECT * FROM ratings'; 
1|1|1|2013-03-22 03:22:01.730235|2013-03-22 03:22:01.730235 

你可以要求的項目,與他們相關的評分和用戶實例,一起這樣的說法:

items = Item.includes(:rated_by_users) 

此執行3個您的SQL查詢:

Item Load (0.1ms) SELECT "items".* FROM "items" 
Rating Load (0.2ms) SELECT "ratings".* FROM "ratings" WHERE "ratings"."item_id" IN (1, 2) 
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (1) 

,並試圖訪問用戶(一個或多個),其額定每個項目可以通過調用每個項目的#rated_by_users聯想法來完成:

> items.map {|item| item.rated_by_users } 
=> [[#<User id: 1, created_at: "2013-03-22 03:21:28", updated_at: "2013-03-22 03:21:28">], []] 
+0

它似乎工作正常!我想這是[這個問題]的答案(http://stackoverflow.com/questions/9642900/eager-loading-the-right-way-to-do-things)?這似乎是堆棧溢出沒有當前答案的問題(鏈接上的答案將所有關聯的對象加載到內存和編程過濾) – thejaz 2013-03-21 09:21:21

+0

我遇到了這個解決方案的問題 - 如果項目A有一個評級,我'在查詢項目B時,我沒有得到項目B.似乎評級的存在阻止了對其他項目的檢索? – thejaz 2013-03-21 19:27:02

+0

如果user_id 1的用戶對項目485有評級,則對user_id 2上的篩選器的項目485的請求不會返回任何項目。 NO RESULT:'SELECT DISTINCT「items」.id FROM「items」LEFT OUTER JOIN「ratings」ON「ratings」。「item_id」=「items」。「id」WHERE(items = 485)AND(ratings.user_id = 2 OR ratings.user_id IS NULL)'RESULT ITEM 485: 'SELECT DISTINCT「items」.id FROM「items」LEFT OUTER JOIN「ratings」ON「ratings」。「wine_id」=「items」。「id」WHERE(items .id = 485)AND(ratings.user_id = 1 OR ratings.user_id IS NULL)' – thejaz 2013-03-21 19:33:16