Добавить ассоциацию (<<) без регистрации в базе данных
Возможно ли в Rails добавить ассоциацию к записи существующей без немедленной фиксации этого изменения в базе данных?
Например. если у меня есть сообщение has_many: tags
post.tags << Tag.first
Это немедленно передаст базу данных. Я пробовал другие способы вместо < <, но без успеха (я хочу создать ассоциацию при сохранении родительского объекта).
Возможно ли получить поведение, например, когда вы добавляете ассоциацию к новой записи со сборкой?
post.tags.build name: "whatever"
Я думаю, что это немного противоречиво в Rails, в некоторых случаях было бы полезно иметь возможность сделать это.
Другими словами, я хочу
post.tags << Tag.first # don't hit the DB here!
post.save # hit the DB here!
Ответы
Ответ 1
Это должно работать в Rails 3.2 и Rails 4:
post.association(:tags).add_to_target(Tag.first)
См. этот сущность: https://gist.github.com/betesh/dd97a331f67736d8b83a
Обратите внимание, что сохранение родителя сохраняет дочерний элемент, а child.parent_id НЕ установлен до его сохранения.
EDIT 12/6/2015:
Для полиморфной записи:
post.association(:tags).send(:build_through_record, Tag.first)
# Tested in Rails 4.2.5
Ответ 2
post_tag = post.post_tags.find_or_initialize_by_tag_id(Tag.first.id)
post_tag.save
Ответ 3
ПРЕДИСЛОВИЕ Это не совсем ответ на этот вопрос, но кто-то, кто ищет такую функциональность, может найти это полезным. Подумайте об этом и других вариантах очень осторожно, прежде чем выпустить его в производственную среду.
В некоторых случаях вы можете использовать отношения has_one, чтобы получить то, что вы хотите. Опять же, действительно рассмотрите то, что вы пытаетесь выполнить, прежде чем использовать это.
Код для рассмотрения
У вас есть отношение has_many
от Trunk
до Branch
, и вы хотите добавить новую ветку.
class Trunk
has_many :branches
end
class Branch
belongs_to :trunk
end
Я также могу связать их друг с другом сингулярно. Мы добавим отношение has_one
к Trunk
class Trunk
has_many :branches
has_one :branch
end
В этот момент вы можете делать такие вещи, как Tree.new.branch = Branch.new
, и вы будете устанавливать отношения, которые не будут сохраняться немедленно, но после сохранения будут доступны из Tree.first.branches
.
Однако это создает довольно запутанную ситуацию для новых разработчиков, когда они смотрят на код и думают: "Ну, какого черта это должно быть, одного или многих?"
Чтобы решить эту проблему, мы можем сделать более разумную связь has_one
с scope
.
class Trunk
has_many :branches
# Using timestamps
has_one :newest_branch, -> { newest }, class_name: 'Branch'
# Alternative, using ID. Side note, avoid the railsy word "last"
has_one :aftmost_branch, -> { aftmost }, class_name: 'Branch'
end
class Branch
belongs_to :trunk
scope :newest, -> { order created_at: :desc }
scope :aftmost, -> { order id: :desc }
end
Будьте осторожны с этим, но он может выполнить функциональные возможности, заданные в OP.