提问人:Orion Edwards 提问时间:11/11/2008 最后编辑:Orion Edwards 更新时间:9/14/2017 访问量:13083
如何在 rails STI 派生模型中禁用验证和回调?
How can I disable a validation and callbacks in a rails STI derived model?
问:
给定一个模型
class BaseModel < ActiveRecord::Base
validates_presence_of :parent_id
before_save :frobnicate_widgets
end
和一个派生模型(底层数据库表有一个字段 - 这是简单的 rails STI)type
class DerivedModel < BaseModel
end
DerivedModel
将以良好的面向对象方式继承 的所有行为,包括 .我想关闭 的验证,并防止回调方法触发,最好不要修改或以其他方式中断BaseModel
validates_presence_of :parent_id
DerivedModel
BaseModel
最简单、最强大的方法是什么?
答:
从在源代码中四处走动(我目前在 rails 1.2.6 上),回调相对简单。
事实证明,如果不使用任何参数调用,etc 方法将返回数组,该数组包含分配给该“回调站点”的所有当前回调before_validation_on_create
before_save
要清除before_save,您可以简单地执行以下操作
before_save.clear
它似乎有效
再次在源代码中四处逛逛,似乎验证可以在每次保存时运行,也可以仅更新/创建。这映射到
:validate
=>所有保存
=仅
>次创作 =仅>更新:validate_on_create
:validate_on_update
要清除它们,您可以使用 ,如下所示:write_inheritable_attribute
write_inheritable_attribute :validate, nil
我喜欢使用以下模式:
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方法来解决这个问题,那就太好了,但这种模式可以很好地工作并处理复杂的交互。
作为 @Jacob Rothstein 的答案的变体,您可以在 parent 中创建一个方法:
class Parent < ActiveRecord::Base
validate_uniqueness_of :column_name, :unless => :child?
def child?
is_a? Child
end
end
class Child < Parent
end
此方法的优点是,无需为需要在 Child 类中禁用验证的每个列名创建多个方法。
评论
validate_uniqueness_of :column_name, :unless => "is_a? Child"
这是我在 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
到目前为止,它对我来说效果很好。
评论
一个更简洁的方法是:
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
- 的实例类是 和 不同于 。
Child
Child
Parent
- 的实例类 是 和 是 的相同。
Parent
Parent
Parent
评论
从 rails 3.0 开始,您还可以访问类方法来操作获取所有验证的列表。但是,您不能通过此数组操作验证集。validators
然而,至少从 rails 5.0 开始,您似乎能够操作(未记录的)方法。_validators
使用此方法,您可以修改子类中的验证,例如:
class Child < Parent
# add additional conditions if necessary
_validators.reject! { |attribute, _| attribute == :parent_id }
end
虽然这使用了一种未记录的方法,但它的好处是不需要超类知道任何关于子类实现的信息。
评论