Rails:使用共享类似复杂属性的ActiveRecord模型保持DRY

时间:2010-05-20 00:12:32

标签: ruby-on-rails ruby activerecord dry

这似乎应该有一个直截了当的答案,但经过很长时间在Google和SO上我找不到它。可能是错过了正确的关键字。

在我的RoR应用程序中,我有几个模型共享特定类型的字符串属性,该属性具有特殊验证和其他功能。我能想到的最接近的类似示例是表示URL的字符串。

这会导致模型中出现大量重复(甚至在单元测试中会出现更多重复),但我不确定如何使其更加干燥。

我可以想到几个可能的方向......

  1. 沿着线创建一个插件 “validates_url_format_of”插件, 但这只会使 验证DRY
  2. 给这个特殊字符串自己的模型,但这看起来很像 沉重的解决方案
  3. 为这个特殊字符串创建一个ruby类,但我该怎么做 ActiveRecord关联此类 使用的模型属性是 db中的字符串
  4. 3号似乎是最合理的,但我无法弄清楚如何扩展ActiveRecord来处理除基本数据类型之外的任何东西。有什么指针吗?

    最后,如果有办法做到这一点,那么在文件夹层次结构中你会把新的类放在一个不是模型的位置吗?

    非常感谢。

    更新

    使用Matt的mixin建议的一个潜在解决方案(并使用URL示例)。注意,这比真正的ruby更接近伪代码,并且旨在传达原理而不是完美的语法。

    首先,创建一个url mixin:

    module Url
      def url_well_formed?
        [...]
      end
    
      def url_live?
        [...]
      end
    end
    

    Site模型中,包含此模块:

    Class Site < ActiveRecord:Base
      include Url
    
      validate :url_well_formed?
    end
    

    当我需要检查网址上的网站是否有效时,请执行...

    if site.url_live?
      [...]
    end
    

    这个问题没有解决的问题是如何让单元测试DRY。如果我有另一个模型,比如Page,它也使用Url mixin,它仍然需要一组重复的URL单元测试。当然,我可以将它们放在帮助器中,但这看起来很混乱。

    是否有更基本的解决方案,或者它是否能够获得最佳解决方案?

2 个答案:

答案 0 :(得分:6)

创建一个抽象模型:

class CommonBase < ActiveRecord::Base
  self.abstract_class = true # makes the model abstract
  validate_format_of :url_field, :with => /.../
end

从抽象模型继承模型:

class User < CommonBase
end

class Post < CommonBase
end

答案 1 :(得分:2)

您可以使用所有常用方法创建模块,然后导入模块? Google为mixins