Rails 4 对象的预加载

Rails 4 eager load for an object

我正在尝试从实例化对象中加载关联,即不是将关联与父对象一起读取...

User.includes(:characters).first

...推迟它,直到我决定它真的需要它并做类似的事情:

u = User.first
# Other stuff ...
u.eager_load(:characters)

在Rails3中我用这个方法增强了ActiveRecord:

def eager_load(*args)
  ActiveRecord::Associations::Preloader.new(self, *args).run
end

而且效果很好。 Rails 4 稍微修改了这部分,我将方法更新为:

def eager_load(*args)
  ActiveRecord::Associations::Preloader.new.preload(self, *args)
end

不幸的是,它现在做了一些奇怪的事情。看一看:

2.1.2 :001 > u = User.first
[2015-01-06 23:18:03] DEBUG ActiveRecord::Base :   User Load (0.3ms)  SELECT  `users`.* FROM `users`  ORDER BY `users`.`id` ASC LIMIT 1
 => #<User id: 1, ...> 
2.1.2 :002 > u.eager_load :characters
[2015-01-06 23:18:07] DEBUG ActiveRecord::Base :   Character Load (0.2ms)  SELECT `characters`.* FROM `characters` WHERE `characters`.`user_id` IN (1)
[2015-01-06 23:18:07] DEBUG ActiveRecord::Base :   Character Load (0.3ms)  SELECT `characters`.* FROM `characters`
[2015-01-06 23:18:07] DEBUG ActiveRecord::Base :   Character Load (0.2ms)  SELECT `characters`.* FROM `characters`
 => [#<ActiveRecord::Associations::Preloader::HasMany:0x00000007c26d28 @klass=Character(id: integer, ...), @owners=[#<User id: ...], @reflection=#<ActiveRecord::Reflection::HasManyReflection:0x0000000496aa60 @name=:characters, ...(LOTS of stuff here)...] 

请特别注意所有记录的两倍 SELECT。有没有办法修复此行为或其他一些方法来做我想做的事?

为了防止重复查询,您实际上应该预先加载您认为会用到的所有内容。所以,你应该像这个例子一样在 documentation:

上嵌套你的 include 命令
users = User.includes(:address, friends: [:address, :followers])

您还可以添加更深层次的关系,例如:

users = User.includes(:address, {friends: [:address, :followers]})

我遇到了同样的问题,回溯我的步骤,我注意到这可能是控制台上 运行 这段代码的产物。每个表达式都会被评估,但我们只对副产品感兴趣:如果是这种情况,请尝试:

u.eager_load(:characters); nil

我希望它有所帮助,我目前正在研究这个,所以这是我迄今为止唯一的观察。