型号:
class Project < ActiveRecord::Base
has_many :user_roles
after_initialize :add_user_roles
def add_user_roles
UserRoles.all.each do |ur|
self.user_roles << ur unless self.user_roles.include?(ur)
end
end
end
查找项目的声明:
@projects = Project.includes(:user_roles)
所以你可以看到,我告诉它在查询中包含用户角色关联。但是,我仍然看到n + 1查询问题:它为每个项目找到一次角色。
如果我从回调中删除self.user_roles
的用法并查看日志,我可以看到它在2个查询中找到项目及其用户角色 - 一个用于项目,一个用于角色使用{ {1}}。
有办法解决这个问题吗?
让我澄清一点:虽然我愿意在需要时解决我的具体情况,但我更喜欢那些专注于如何解决问题的答案。我能够编写一个kludge来使数据处于我想要的状态而不使用after_initialize回调,因此不会进入n + 1查询问题。但是,我宁愿不这样做,所以我更喜欢一般问题的答案而不是我的具体例子。
答案 0 :(得分:6)
看看rails eager loading http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
您可以使用includes
User.find(2).includes(:assets)#will load all assets with user
或者您可以在模型中指定急切加载关联
应用程序/模型/ user.rb
class User< AR::Base
has_many :posts,:include=>:comments
end
class Post < AR::Base
has_many :comments
belongs_to :user
end
现在u.posts
将为每个帖子加载评论
答案 1 :(得分:1)
这可能是由after_initialize回调引起的,每次初始化每个对象时都会运行该回调。如果回调点是自动为每个用户分配每个角色(除非已经分配),那么您可以通过before_save
过滤器来完成此操作。这样,在执行Project.includes(:user_roles)
查找程序时,代码将无法运行。
答案 2 :(得分:1)
即使是在after_initialize
中也没有加载加载的关联(在初始化记录后,它们会被加载)。有关讨论,请参阅此Rails问题:
https://github.com/rails/rails/issues/13156
与原始问题相关:看起来每个项目都有相同的UserRole
个对象集。我猜测有一个has_many :through
被消毒了,但即便如此,Project
怎么会没有全套?我没有看到Project
和UserRole
在这里实际连接的方式 - 从示例中可见的内容来看:
class Project < ActiveRecord::Base
def user_roles
UserRole.all
end
end
会完成与after_initialize
...