假设我有一个ActiveRecord关联,如:
class City < ActiveRecord::Base
belongs_to :state
end
没有州的城市应无效。似乎这两种都是可能的验证:
validates :state, presence: true
# OR
validates :state_id, presence: true
我猜他们是完全相同的,因为:
belongs_to
创建方法state
和state=
state=
设置state_id
但是,我刚刚修改了一个失败的规范,通过更改它来检查id而不是对象。
这两种验证方式都可以接受吗?如果是这样,你何时会使用其中一个?
答案 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
但我知道这些人知道他们的东西。