何时使用"validates_associated"v."belongs_to:parent,:validate => true"

Pet*_*xey 29 activerecord ruby-on-rails

似乎在rails中你可以在两个地方定义关联验证,或者在关联本身上:

class Child

  belongs_to :parent, :validate => true

end
Run Code Online (Sandbox Code Playgroud)

或者作为验证回调:

class Child

  belongs_to :parent

  validates_associated :parent

end
Run Code Online (Sandbox Code Playgroud)

这两种方法有什么区别?

测试差异

我想也许前者会创建一个背压,并强制父母只有在孩子有效的情况下才有效:

即(设置时:validate => true)

child.valid? # => false
child.parent.valid? # => also evaluates to false because of the :validate => true condition


# do whatever it takes to make the child valid again
#...
child.valid? # => true
child.parent.valid? # => true
Run Code Online (Sandbox Code Playgroud)

但是我测试了它,但这不会发生.那两种方法之间有什么区别(如果有的话)?

Mik*_* A. 41

我不得不深入研究Rails(3.0.7)代码以找到一些差异.核心功能对我来说看起来是一样的 - 它们似乎都会调用valid?相关的记录.

我发现的主要区别仅在使用该:autosave功能时或者在销毁相关对象或将其标记为销毁时才会出现.例如,我有:

class AbsentDate < ActiveRecord::Base
  belongs_to :user, :autosave => true, :validate => true
end
Run Code Online (Sandbox Code Playgroud)

我看到以下行为:

user = User.new(:username => "Jimmy")
user.valid?                               # => true
ad = AbsentDate.new(:user => user)
user.username = nil                          
user.valid?                               # => false
ad.valid?                                 # => false
ad.errors.full_messages                   # => ["User username cannot be empty"]
ad.user.mark_for_destruction
ad.valid?                                 # => true
Run Code Online (Sandbox Code Playgroud)

请注意,标记用户进行销毁会导致有效的AbsentDate.另请注意,只有一条错误消息.现在考虑这种情况:

class AbsentDate < ActiveRecord::Base
  belongs_to :user, :autosave => true
  validates_associated :user
end
Run Code Online (Sandbox Code Playgroud)

这就是我看到的情况:

user = User.new(:username => "Jimmy")
user.valid?                                # => true
ad = AbsentDate.new(:user => user)
user.username = nil
user.valid?                                # => false
ad.valid?                                  # => false
ad.errors.full_messages                    # => ["User username cannot be empty", "User is invalid"]
ad.user.mark_for_destruction
ad.valid?                                  # => false
Run Code Online (Sandbox Code Playgroud)

这次有两条错误消息,即使其用户已被标记为销毁,AbsentDate仍然是假的.我能够通过调用destroy而不是mark_for_destruction来复制这些结果.

最后一两件事:如果你使用validates_associated,你会得到几个选项(:if,:unless,:on,:message),如果你使用的国旗上,你不会有belongs_to.