11

假设我有一个 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 而不是对象来修复失败的规范。

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

4

4 回答 4

16

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

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

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

基本上如果 City 中使用的外键(用于 state_id)都作为 State 中的实际记录存在,效果是一样的。如果您的状态代码无效,差异将显示出来。

于 2012-07-27T20:43:10.973 回答
1

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

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

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

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

于 2012-07-27T21:20:05.357 回答
0

就个人而言,我更喜欢让模型更健壮并接受或。因此,在您的特定情况下, City 可以接受Stateobject 或 a 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

编辑:删除了验证语句中的双重否定。原本有unless: proc{|c| !c.state_id.blank? }

于 2013-08-22T14:52:58.653 回答
-1

根据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

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

于 2015-04-15T21:27:58.943 回答