Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何在Rails中替换内存中的模型关联?_Ruby On Rails_Activerecord_Rails Activerecord - Fatal编程技术网

Ruby on rails 如何在Rails中替换内存中的模型关联?

Ruby on rails 如何在Rails中替换内存中的模型关联?,ruby-on-rails,activerecord,rails-activerecord,Ruby On Rails,Activerecord,Rails Activerecord,假设我有一个人模型,一个人有很多宠物,一只宠物与狗和猫有多态性关联。请注意,一个人不能有他/她过敏的动物 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? err

假设我有一个人模型,一个人有很多宠物,一只宠物与狗和猫有多态性关联。请注意,一个人不能有他/她过敏的动物

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
鲍勃喜欢爱丽丝,但阿黛尔是一只非常好斗的猫,所以鲍勃不再想要它了。他还想要一只狗。因此,他决定向其端点执行PUT请求。3是狗杰克的身份证,1是猫爱丽丝的身份证

PUT /me/ {
  "pets": {
    "dog_ids": [3],
    "cat_ids": [1]
  }
}
现在问题来了

如何在内存中替换Bob的宠物,验证Bob以确保他对任何宠物都不过敏,然后保存关联(不使用数据库事务)

我知道可以使用
#build
在内存中创建关联,但我不想附加到现有关联,而是在保存之前替换现有关联,全部在内存中。因此,上面的示例将在验证Person实例后执行两个数据库查询,一个用于为Jack the dog创建宠物关联,另一个用于在验证后删除Adele the cat的关联

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
      .reject(&:marked_for_destruction?)
      .any? { |pet| pet.animal_type == Cat.name }
  end

  def owns_a_dog?
    pets
      .reject(&:marked_for_destruction?)
      .any? { |pet| pet.animal_type == Dog.name }
  end
end


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)

jack = Dog.create

bob.pets.find_by(animal_type: Cat.name, animal_id: adele.id).mark_for_destruction

bob.pets.build(animal: jack)
bob.valid?
bob.save!
我试图操纵
ActiveRecord::Associations::CollectionProxy
,但在删除或添加元素时,它总是在数据库中提交

请注意,我不想创建一个param验证器,只想验证id,其他接口可以用来更新个人,并且验证需要在所有这些接口之间保持一致,并且接近模型

编辑


我尝试将
#build
#mark#u一起使用以进行销毁
,但是如果替换不起作用,保存后将重新创建现有关联。

您可以使用
pets=
方法直接分配集合。比如说,

# Find the first pet
p1 = bob.pets.find_by_animal_id(alice.id)

# Create the second pet, this won't save yet
jack = Dog.find(3)
p2 = Pet.new(animal: jack)

bob.pets = [p1, p2]

我刚刚提出了一个解决方案:

如果
动物id
不在提供的id中,则标记要销毁的宠物,构建不存在的动物,并跳过验证中标记要销毁的动物

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
      .reject(&:marked_for_destruction?)
      .any? { |pet| pet.animal_type == Cat.name }
  end

  def owns_a_dog?
    pets
      .reject(&:marked_for_destruction?)
      .any? { |pet| pet.animal_type == Dog.name }
  end
end


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)

jack = Dog.create

bob.pets.find_by(animal_type: Cat.name, animal_id: adele.id).mark_for_destruction

bob.pets.build(animal: jack)
bob.valid?
bob.save!
class-Person
执行
bob.pets=[p1,p2]
将在数据库中保存宠物关联。我想在执行任何数据库事务之前,将pets分配给内存中的bob以验证bob。理论上这显然是可能的,但ActiveRecord不允许我这么做。