Желание загрузить ассоциацию сингулярной ассоциации из объекта ActiveRecord, созданного в Rails 5
У меня есть модель User
, у которой has_one :child
, а Child
model has_one :toy
.
Если у меня есть один экземпляр пользовательского класса 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 :(
Есть ли способ сделать это, что не требует повторного запроса модели пользователя. то есть. Я хочу избежать этого
User.where(id: user.id).eager_load(child: :toy).first
Декларации модельной модели:
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
Обновить
Это работает, но не идеально. Я не думаю, что мне пришлось бы объявить другое отношение исключительно по этой причине.
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
который позволяет мне вызвать user.child_with_toy
чтобы получить объект Child
, и user.child_with_toy.toy
чтобы получить объект Toy
, только вызывая один SQL-запрос.
Ответы
Ответ 1
Если вы хотите, чтобы загрузить ассоциацию сингулярной ассоциации для уже созданной записи, вы можете сделать это:
user.association(:child).target = user.association(:child).scope.eager_load(:toy).first
Это похоже на один из подходов, перечисленных в верхней части вашего вопроса. В частности, обратите внимание на часть .target
.
ActiveRecord
не оптимизирован для этого конкретного сценария, поэтому код довольно уродлив. По этой причине я бы сильно :child_with_toy
к вашему подходу :child_with_toy
если вам действительно нужно сохранить запрос.