2013-03-21 48 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