渴望从Rails 5中的实例化ActiveRecord对象加载单一关联的关联

you*_*786 13 ruby-on-rails rails-activerecord

我有一个模型User,那个has_one :childChild模型has_one :toy.

如果我有一个User类的单个实例,user我如何在一个查询中加载子和玩具?

这是不起作用的:

user.child.toy # 2 queries
user.includes(child: :toy) # can't call includes on a single record
user.child.includes(:toy) # same as above
user.association(:child).scope.eager_load(:toy).first # makes the appropriate query with both child and toy... but doesn't set the object on the user model.
user.child = user.association(:child).scope.eager_load(:toy).first # makes the appropriate query, but also calls another query before setting the child :(
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点,不涉及重新查询用户模型.即.我想避免这种情况

User.where(id: user.id).eager_load(child: :toy).first
Run Code Online (Sandbox Code Playgroud)

Relavant模型声明:

class User < ActiveRecord::Base
  has_one :child
  has_one :toy, through: :child
end

class Child < ActiveRecord::Base
  has_one :toy
  belongs_to :user
end

class Toy < ActiveRecord::Base
  belongs_to :child
end
Run Code Online (Sandbox Code Playgroud)

更新

这有效,但并不理想.我认为我不应仅仅因为这个原因宣布另一种关系.

class User < ActiveRecord::Base
  has_one :child
  has_one :toy, through: :child
  has_one :child_with_toy, ->{ eager_loads(:toy) }, class_name: "Child", foreign_key: :parent_id
end
Run Code Online (Sandbox Code Playgroud)

这允许我调用user.child_with_toy获取Child对象,并user.child_with_toy.toy获取Toy对象,同时只触发一个SQL查询.

Nat*_*han 10

如果您希望为已经实例化的记录急切加载单个关联的关联,则可以执行以下操作:

user.association(:child).target = user.association(:child).scope.eager_load(:toy).first
Run Code Online (Sandbox Code Playgroud)

这类似于您在问题顶部列出的方法之一.特别注意这.target部分.

ActiveRecord没有针对此特定方案进行优化,因此代码非常难看.因此,:child_with_toy如果您确实需要保存查询,我会强烈倾向于您的方法.


Dmi*_*kin 5

可以通过以下方法更轻松地完成Preloader

ActiveRecord::Associations::Preloader.new.preload(user, child: [:toy])
Run Code Online (Sandbox Code Playgroud)