我应该何时验证ActiveRecord关联对象与其ID的存在?

时间:2012-07-27 20:32:24

标签: ruby-on-rails ruby activerecord

假设我有一个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 个答案:

答案 0 :(得分:14)

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

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

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

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

答案 1 :(得分:1)

如果您执行类似

的操作,该怎么办?
s = State.new
c = City.new
c.state = s
c.valid?

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

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

答案 2 :(得分:0)

就个人而言,我更喜欢允许模型更强大并接受或者。因此,在您的特定情况下,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? }

答案 3 :(得分:-1)

根据Rails 4 Way by Obie Fernandez

  

当您尝试确保存在关联时,请传递它   外键属性,而不是关联变量本身

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

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