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

Ruby on rails 我应该在什么时候验证ActiveRecord关联对象与其id的存在性?,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,假设我有一个ActiveRecord关联,如: class City < ActiveRecord::Base belongs_to :state end 我猜它们是一样的,因为: 属于创建方法state和state= state=设置state\u id 但是,我刚刚修复了一个失败的规范,将其更改为检查id而不是对象 这两种验证方法都可以接受吗?如果是这样,您什么时候会使用一个或另一个?验证:state将使用从城市到州(所属对象)的关系以及外键,而验证:state\u id仅使

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

class City < ActiveRecord::Base
  belongs_to :state
end
我猜它们是一样的,因为:

  • 属于
    创建方法
    state
    state=
  • state=
    设置
    state\u id
但是,我刚刚修复了一个失败的规范,将其更改为检查id而不是对象


这两种验证方法都可以接受吗?如果是这样,您什么时候会使用一个或另一个?

验证:state
将使用从城市到州(所属对象)的关系以及外键,而
验证:state\u id
仅使用列state\u id,并查看它是否有任何值

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

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


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

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

s = State.new
c = City.new
c.state = s
c.valid?
我还没有尝试过这个方法,但是我猜,如果您正在检查c.state_id的存在,它将丢失,即使c确实有一个状态(因为id还没有生成,因为状态还没有保存)


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

就我个人而言,我更喜欢让模型更健壮,并接受或。因此,在您的特定情况下,City可以接受
State
对象或
State\u 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
class City
Edit:删除了validate语句中的双负片。最初有
除非:proc{c | c |!c.state_id.blank?}

根据:

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

这本书没有解释为什么你应该用这个来代替它

validates :region, :presence => true

但我知道这些家伙知道他们的本事。

我们能看看你的原始和固定规格吗?我喜欢你的方法。挑剔:没有必要使用
,除非!空白?
;如果
为空?
除非存在?
都可以。这是非常正确的,我要把
存在?
放进去,因为这只是
的倒数!空白?
,但我更喜欢
的可读性!空白
。但是,如果为空,则执行
操作?
在没有双重否定:p的情况下也可以正常工作。这与
验证:区域,存在:true
类似,只是它还强制检查数据库中是否存在关联。这样做似乎有点奇怪,因为它不提供内存对象的验证。根据经验,只验证对象并添加外键约束以确保键始终有效更容易。但这一点很好。可能是因为性能原因,因为validates:region每次验证对象时都会从DB加载region,而validates:region\u id不会这样做。
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