2010-12-02 68 views
1

我找到了一种方法来完成这项工作,但我对好的方式/ Rails 3方式感到好奇。 (我仍然使用2.3.5,但希望在新年前后迁移。)如何在多代模块中定义/附加导轨验证

情况:我有两层模块继承,第二层被混合到Rails模型中。这两个模块定义的验证方法,我想他们都在验证连接到基础类,但由于继承的两个层次,下面不工作:

def self.included(base) 
    base.validate :yadda_yadda 
end 

当包括该模块由另一个模块,解释器研磨到尖锐的停顿,因为模块不知道约ActiveRecord::Validations。包括验证模块会引起“save?”的问题。感谢alias_method

以下的工作,只要你记得打电话super,只要你覆盖validate()。我不相信自己或未来的维护者要记住这一点,所以如果可能的话,我想使用validate :yadda_yadda成语。

module Grandpa 

    def validate 
    must_be_ok 
    end 

    def must_be_ok 
    errors.add_to_base("#{self} wasn't ok") 
    end 

end 

module Dad 

    include Grandpa 

    def validate 
    super 
    must_be_ok_too 
    end 

    def must_be_ok_too 
    errors.add_to_base("#{self} wasn't ok either") 
    end 

end 

class Kid < ActiveRecord::Base 

    include Dad 

    validate :must_be_ok_three 

    def must_be_ok_three 
    errors.add_to_base("#{self} wasn't ok furthermore") 
    end 

end 

建议? Rails 3的方法?我认为验证API没有太大改变。

+0

那么要清楚你想要跨多个模型共享验证? – jonnii 2010-12-02 20:43:23

回答

0

我解决了它(当我遇到同样的问题,但与验证以外的东西)。

简短回答:您可以在要引入的模块上调用send(:included,base)。在上面的included()定义中,您需要检查基类是Class还是Module。

为什么你会想要这样做?那么,我有一些模块可以从我的模型中提取一些常用的功能。例如,模块HasAllocable设置多态性关系,并为虚拟属性设置一个getter/setter对。现在我有另外一个模块需要拉入HasAllocable,以便让基类不必记住它。

我很想知道这是否对任何人都有趣。我在网上没有看到任何类似的东西,所以我想知道模型继承的多层更多是反模式。

module Grandpa 

    def self.included(base) 
    if base.kind_of?(Class) 
     base.validate :must_be_ok 
    end 
    end 

end 

module Dad 

    include Grandpa 

    def self.included(base) 
    if base.kind_of?(Class) 
     # you can do this 
     #base.send(:include, Grandpa) 
     # you can also do this 
     Grandpa.send(:included, base) 
     # this does not invoke Grandpa.included(Kid) 
     #super(base) 

     base.validate :must_be_ok_too 
    end 
    end 

end 

class Kid < ActiveRecord::Base 
    include Dad 
    validate :must_be_ok_three 
end