两个Rails模型之间的关联,允许使用validates_associated进行验证

时间:2014-09-06 04:34:37

标签: ruby-on-rails ruby-on-rails-3 validation

使用Rails 3.2,不确定是否会产生影响

Owner has_many Bicycles

我想根据Bicycles模型上Owner字段的值,限制bicycle_limit可以拥有的Owner个数存储该所有者的允许限制。

目前,我希望limit_bicycle_ownership验证能够在验证/保存BicycleOwner时运行(我稍后会限制它)。为此,我已将validates_associated: :owner放在Bicycle模型上。

class Owner < ActiveRecord::Base
 has_many :bicycles, inverse_of: :owner

 validate :limit_bicycle_ownership

 def limit_bicycle_ownership
   if bicycles(:reload).size > bicycle_limit
     errors.add(:bicycles, "^Too many bicycles")
   end
 end
end

class Bicycle < ActiveRecord::Base
  belongs_to :owner, inverse_of: :bicycles

  validates_presence :owner
  validates_associated: :owner
end

当使用以下方式通过Owner模型的实例设置或更改自行车的所有权时,此设置的行为与预期相同:

owner = Owner.create(bicycle_limit: 1)
owner.bicycles << Bicycle.create()
owner.valid? # true
owner.bicycles << Bicycle.create()
owner.valid? # false

但是,当通过Bicycle模型的实例更改所有权时,验证似乎不起作用:

owner = Owner.create(bicycle_limit: 1)

bicycle1 = Bicycle.new(owner_id: owner.id)
bicycle1.valid? # true
owner.valid? # true
bicycle1.save! # true

bicycle2 = Bicycle.new(owner_id: owner.id)
bicycle2.valid? # true
owner.valid? # true
bicycle2.save! # true, but I was expecting this to fail
owner.valid? # false

我已经撬开了limit_bicycle_ownership验证,据我所知,这是自行车2的过程!运行:

  • bicycle2了解与owner的新关联,以通过validates_association :owner回调验证
  • owner但是,似乎没有任何关于现在导致其验证的关联的知识,并且bicycles(:reload)仅返回与bicycle1的现有关联
  • owner上的验证然后通过,因为就owner而言,它只拥有一个自行车(bicycle1),但不超过它bicycle_limit的1
  • bicycle2然后继续验证并保存,并成功保存,让owner拥有两辆自行车

所以基本上在设置或更新自行车的拥有者时,其新主人甚至不知道自行车是否存在,直到自行车完成保存,此时执行validates_associated呼叫为时已晚。有关更好的方法的任何想法,而不必复制Owner模型中Bicycle模型的验证逻辑?我觉得可能有一个解决方案涉及after_save模型上的Bicycle回调,但我真的不知道从哪里开始。

1 个答案:

答案 0 :(得分:0)

我认为你可以在自行车添加到所有者时启动交易,如果添加所有者后无效则回滚:

Bicycle.transaction do
  bicycle2 = Bicycle.new(owner_id: owner.id)
  bicycle2.valid? # true
  owner.valid? # true
  bicycle2.save!

  if !owner.valid?
   raise ActiveRecord::Rollback, "Error message..."
  end
end