Ruby on rails 活动记录:与参数的即时加载关联

Ruby on rails 活动记录:与参数的即时加载关联,ruby-on-rails,ruby-on-rails-3,activerecord,Ruby On Rails,Ruby On Rails 3,Activerecord,我有以下型号: class Rating < ActiveRecord::Base belongs_to :item belongs_to :user end class Item < ActiveRecord::Base has_many :ratings end …但这不会给我没有评分的项目 我的第一个想法是与一个参数有很多关联,然后用includes方法传递该参数。但这似乎并不存在 如何在不进行N+1查询或将所有实体加载到内存中的情况下,将所有帖子和已加载的关联

我有以下型号:

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

class Item < ActiveRecord::Base
  has_many :ratings
end
…但这不会给我没有评分的项目

我的第一个想法是与一个参数有很多关联,然后用includes方法传递该参数。但这似乎并不存在


如何在不进行N+1查询或将所有实体加载到内存中的情况下,将所有帖子和已加载的关联过滤到一个参数上?

看起来您基本上是在建模一个has\u many:through关系:Item has\u和\u beliens\u to \u many User,而评级是连接模型。您可以阅读:通过中的关系

如果是这种情况,我建议您使用has_many:to构建模型关系,如下所示:

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
您可以使用以下语句请求所有项目及其关联的评级和用户实例:

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 association方法,可以尝试访问对每个项目进行评级的用户:

> 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">], []] 
第一步

使当前用户在模型层中可访问一项技术概述如下:

步骤2

添加与在运行时得到评估的条件的关联

轨道2

正如我在最近的一篇文章中所写的那样,我建议您:

items = Item.all
ActiveRecord::Associations::Preloader.new.preload(items, :ratings, Rating.where(user_id: user_id))

您可以使用预加载程序和access项的自定义范围。每个{i{i.ratings}的范围都已由用户确定。

检查此链接。请包括用户model@AbibullahRahamathulah这个问题是关于静态论证的,它有很多条件,而不是dynamic@gabrielhilal用户模型是空的,似乎工作正常!我想这也是问题的答案吧?这似乎是一个问题,堆栈溢出上没有当前答案链接上的答案将所有关联对象加载到内存中并按程序筛选我遇到了此解决方案的问题-如果项目a有一个评级,而我正在查询项目B,我没有得到项目B。评级的存在似乎阻止了对其他项目的检索?如果用户id为1的用户对项目485有评级,则对用户id为2的过滤器的项目485的请求不会返回任何项目。无结果:从项目左侧外部连接评级中选择不同的项目.id,其中项目=485和评级。用户\u id=2或评级。用户\u id为空结果项目485:从项目左侧外部连接评级中选择不同的项目.id,其中项目.id=485和评级。用户\u id=1或评级。用户\u id为空现在看。我已经用一个更好的解决方案完全重写了我的答案,请再看一看,但你的解决方案不会过滤用户?在不执行N+1查询的情况下,这可能吗?工作非常完美!一个小提示:您链接到的步骤1中的答案没有注意到线程变量不会在请求之间共享。我使用gem request_store来简化当前用户的存储,并确保不会泄露。是的,看起来thin和puma服务器有问题。顺便说一句,gem使用Thread.current store,他们在调用后将其清除。我已在步骤1中建议的解决方案中修复了线程泄漏问题。我认为将当前用户带到模型层是错误的。对于这种情况,有更好的解决方案。
> 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">], []] 
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
class Item < ActiveRecord::Base
  has_many :ratings
  has_many :current_user_ratings, 
           :class_name => "Rating", 
           :conditions => proc { ["ratings.user_id = ?", User.current_user.try(:id)] }
end
Item.includes(:current_user_ratings)
items = Item.all
ActiveRecord::Associations::Preloader.new.preload(items, :ratings, Rating.where(user_id: user_id))