Предположим, у меня есть модель Person, что у Человека много домашних животных, а у Pet есть полиморфная связь с собакой и кошкой. Обратите внимание, что у человека не может быть животное, у которого у него аллергия.Как заменить ассоциации моделей в памяти в Rails?
class Person < ActiveRecord::Base
has_many :pets, dependent: :destroy
validate :not_allergic_to_animal
def not_allergic_to_animal
if allergic_to_cats? && owns_a_cat?
errors.add(:pets, 'cannot have a cat if allergic to cats')
elsif allergic_to_dogs? && owns_a_dog?
errors.add(:pets, 'cannot have a dog if allergic to dogs')
end
end
def owns_a_cat?
pets.any? { |pet| pet.animal_type == Cat.name }
end
def owns_a_dog?
pets.any? { |pet| pet.animal_type == Dog.name }
end
end
class Pet < ActiveRecord::Base
belongs_to :user
belongs_to :animal, polymorphic: true
validates :animal_type, inclusion: { in: [Cat.name, Dog.name] }
end
class Cat < ActiveRecord::Base
end
class Dog < ActiveRecord::Base
end
Теперь предположим, что у человека Bob уже есть 2 кошки, одна по имени Алиса, а другая по имени Адель.
bob = Person.where(name: 'Bob')
alice = Cat.where(name: 'Alice')
bob.pets.create!(animal: alice)
adele = Cat.where(name: 'Adele')
bob.pets.create!(animal: adele)
Боб любит Алису, но Адель - действительно агрессивная кошка, поэтому Боб больше этого не хочет. Он также хочет собаку. Поэтому он решает сделать запрос PUT к своей конечной точке. 3 - это идентификатор Джека, а 1 - идентификатор Алисы кошки.
PUT /me/ {
"pets": {
"dog_ids": [3],
"cat_ids": [1]
}
}
Теперь вопрос!
Как я могу заменить домашних животных Боба в память, подтвердите Боба, чтобы убедиться, что у него нет аллергии на кого-либо из его домашних животных, а затем сохранить ассоциации (без использования транзакции с базой данных)?
Я знаю, что можно создавать объединения в памяти с помощью #build
, но я не хочу, чтобы добавить к существующим объединениям, но заменить уже существующие, все в памяти перед сохранением. Поэтому приведенный выше пример выполнил бы 2 запроса базы данных после проверки экземпляра Person, один для создания ассоциации Pet для Jack the dog, а другой - для удаления ассоциации для Adele the cat, после проверки.
Я пытался манипулировать ActiveRecord::Associations::CollectionProxy
, но он всегда фиксируется в базе данных при удалении или добавлении элемента.
Обратите внимание, что я не хочу создавать валидатор параметров и просто проверять идентификаторы, другие интерфейсы могут использоваться для обновления Person, а проверка должна быть согласованной во всех этих интерфейсах и близка к модели.
Редактировать
Я попытался с помощью #build
в сочетании с #mark_for_destruction
, а также, но замена не будет работать, существующие ассоциации будут воссозданы после сохранения.
Выполнение 'bob.pets = [p1, p2]' сохранит ассоциацию домашних животных в базе данных. Я хочу назначить домашних питомцев в память для проверки боба перед выполнением любой транзакции базы данных. Теоретически это возможно, но ActiveRecord не позволяет мне это делать. –