20

给定一个模型

class BaseModel < ActiveRecord::Base
  validates_presence_of :parent_id
  before_save :frobnicate_widgets
end

和一个派生模型(底层数据库表有一个type字段 - 这是简单的 rails STI)

class DerivedModel < BaseModel
end

DerivedModel将以良好的 OO 方式继承所有行为BaseModel,包括validates_presence_of :parent_id. 我想关闭验证DerivedModel,并防止触发回调方法,最好不要修改或以其他方式破坏BaseModel

最简单、最可靠的方法是什么?

4

7 回答 7

46

我喜欢使用以下模式:

class Parent < ActiveRecord::Base
  validate_uniqueness_of :column_name, :if => :validate_uniqueness_of_column_name?
  def validate_uniqueness_of_column_name?
    true
  end
end

class Child < Parent
  def validate_uniqueness_of_column_name?
    false
  end
end

如果 rails 提供了一个 skip_validation 方法来解决这个问题,那就太好了,但是这种模式可以很好地处理复杂的交互。

于 2009-03-28T08:27:11.643 回答
9

作为@Jacob Rothstein 答案的变体,您可以在父级中创建一个方法:

class Parent < ActiveRecord::Base
  validate_uniqueness_of :column_name, :unless => :child?
  def child?
    is_a? Child
  end
end

class Child < Parent
end

这种方法的好处是您不需要为需要在 Child 类中禁用验证的每个列名创建多个方法。

于 2012-04-18T11:06:20.417 回答
3

通过在源代码中四处寻找(我目前在 rails 1.2.6 上),回调相对简单。

事实证明,如果不使用任何参数调用before_validation_on_create, before_saveetc 方法,将返回包含分配给该“回调站点”的所有当前回调的数组

要清除 before_save 的,你可以简单地做

before_save.clear

它似乎工作

于 2008-11-10T23:45:46.630 回答
2

一种更清洁的方法是:

class Parent < ActiveRecord::Base
  validate :column_name, uniqueness: true, if: 'self.class == Parent'
end


class Child < Parent
end

或者你也可以这样使用它:

class Parent < ActiveRecord::Base
  validate :column_name, uniqueness: true, if: :check_base

  private

  def check_base
    self.class == Parent
  end
end


class Child < Parent
end

因此,如果模型的实例类是 ,则完成唯一性验证Parent

  1. 的实例类ChildChild 并且不同于Parent
  2. 的实例类ParentisParent和 相同Parent
于 2015-02-25T20:40:19.887 回答
2

从 Rails 3.0 开始,您还可以访问validators 类方法来操作获取所有验证的列表。但是,您不能通过此 Array 操作验证集。

至少从 rails 5.0 开始,您似乎能够操纵_validators(未记录的)方法。

使用此方法,您可以修改子类中的验证,例如:

class Child < Parent
  # add additional conditions if necessary
  _validators.reject! { |attribute, _| attribute == :parent_id } 
end

虽然这使用了一个未记录的方法,但它的好处是不需要超类知道任何关于孩子的实现。

于 2017-09-14T07:41:07.010 回答
0

再次在源代码中四处寻找,似乎可以在每次保存时运行验证,或者仅在更新/创建时运行。这映射到

:validate=> 所有保存
:validate_on_create=> 仅创建
:validate_on_update=> 仅更新

要清除它们,您可以使用write_inheritable_attribute,如下所示:

write_inheritable_attribute :validate, nil
于 2008-11-10T23:47:38.547 回答
0

这是我在mongoid 3中使用的 RubyDev 的一个细微变化。

class Parent
  include Mongoid::Document
  validates :column_name , uniqueness: true, unless: Proc.new {|r| r._type == "Child"}
end

class Child < Parent
end

到目前为止,它对我来说一直很好。

于 2013-01-30T07:29:08.393 回答