Подтвердить что ты не робот

Добавить ассоциацию (<<) без регистрации в базе данных

Возможно ли в 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!
4b9b3361

Ответ 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.