我应该在什么时候验证ActiveRecord关联对象与其id的存在性



假设我有一个ActiveRecord关联,比如:

class City < ActiveRecord::Base
  belongs_to :state
end

一个没有州的城市应该是无效的。似乎这两种都是可能的验证:

validates :state,    presence: true
# OR
validates :state_id, presence: true

我猜它们是相同的,因为:

  • belongs_to创建方法statestate=
  • state=设置state_id

然而,我刚刚修复了一个失败的规范,将其更改为检查id而不是对象。

这两种验证方式都可以接受吗?如果是,你什么时候会使用其中一个?

validates :state将使用从城市到州的关系(belongs_to)以及外键,而validates :state_id单独使用列state_id并查看它是否有任何值。

我的首选方法是验证state(关系),因为这需要同时存在密钥和关系。

验证state_id将起作用,因为它将确保状态id存在,但不会检查代码的有效性,即对于City中的任何给定状态密钥,状态实际上"存在"。

基本上,如果City中使用的外键(用于state_id)都作为state中的实际记录存在,则效果相同。如果状态中有一个无效的状态代码,则会显示差异。

如果你做了类似的事情会怎么样

s = State.new
c = City.new
c.state = s
c.valid?

我还没有尝试过,但我猜,如果你检查c.state_id的存在,它会丢失,即使c确实有状态(因为id还没有生成,因为状态还没有保存)。

也就是说,如果你关心的是国家的存在,你应该验证国家的存在。

就我个人而言,我更喜欢让模型更健壮,并接受非此即彼。因此,在您的特定情况下,City可以接受State对象或state_id对象,但需要发送其中一个。

class City < ActiveRecord::Base
  attr_accessible :state, :state_id
  validates :state,    presence: true, if: proc{|c| c.state_id.blank? }
  validates :state_id, presence: true, if: proc{|c| c.state.blank?    }
  belongs_to :state
end

编辑:删除validate语句中的双负数。最初有unless: proc{|c| !c.state_id.blank? }

根据Obie Fernandez的Rails 4 Way:

当您试图确保关联存在时,通过外键属性,而不是关联变量本身

validates :region_id, :presence => true
validate :region_exists
def region_exists
  errors.add(:region_id, "does not exist") unless Region.exists?(region_id)
end

这本书没有解释为什么你应该使用这个而不是

validates :region, :presence => true

但我知道这些家伙知道他们的东西。

最新更新