【问题标题】:How to mix in additional validations to ActiveModel::Model?如何在 ActiveModel::Model 中加入额外的验证?
【发布时间】:2013-10-04 21:42:23
【问题描述】:

我有一个包含 ActiveModel::Model 模块的表单类,以便进行基本验证

class RegistrationForm
  include ActiveModel::Model
  ...
  validates_presence_of ....
end

我想添加一些额外的类验证方法,如下所示

class RegistrationForm
  include ActiveModel::Model
  ...
  my_custom_class_validation_method
end

并且我希望在包含 ActiveModel::Model 模块时自动包含此方法。

我尝试使用像这里这样的解决方案:adding class methods to ActiveRecord::Base 但没有运气。

这可能吗?

【问题讨论】:

    标签: ruby-on-rails ruby validation metaprogramming mixins


    【解决方案1】:

    好的。 还有一个sn-p。 我不确定,但是这个怎么样?

    # This should be locate in lib/your_custom_validator.rb
    class YourCustomValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        # validation login is here
      end
    end
    
    I think, now you can use that validator in any model. 
    
    
    # You can use that validator like this. 
    class RegistrationForm < ActiveRecord::Base
      validates :some_column_name, your_custom_validator: true
    end
    

    干杯,桑吉尔。

    【讨论】:

    • 谢谢@humbroll。这种方法没有任何问题,并在验证的情况下解决了我的问题。但是,当我包含 ActiveModel::Model 时,我仍然很好奇这是否可以向我的表单类添加另一个类方法(不同于验证方法)。这就是 Ruby,一定有办法实现这个...
    【解决方案2】:

    这段代码 sn-p 可能是一个好的开始。

    module ActiveModel
      module Model
        def self.included(base)
          base.extend(ClassMethods)
          base.class_eval %{
                class << self
                  def your_custom_validator
                  end
                end  
              }
        end
      end
    end
    

    【讨论】:

    • 经过一些调整后,我强制这个 sn-p 开始工作——但这​​不是我想要的方式。我必须从 Rails 源中复制 self.included 函数的内容,然后使用 class_eval 添加该片段。由于未知原因,仅调用 super() 不起作用。完整的工作代码在这里:gist.github.com/chrosciu/6834015 这个解决方案强烈依赖于 ActiveModel::Model 的内部实现并且可能变得脆弱...... :( 但是感谢您的回答。
    • 您要求的是 ActiveModel::Model 引入您的自定义代码,因此此建议似乎与此一致。如果没有真正的猴子补丁ActiveModel::Model,它怎么知道包含你的自定义验证器。我同意这有点脆弱,这就是为什么您使用ExtendedModel 的其他方法很有意义。这样,您就明确地制作了一个新的 ActiveModel::Model 自定义版本,该版本仅适用于您的应用程序。绝对不那么脆弱。这是一个有趣的深思熟虑的线程/问题。
    【解决方案3】:

    另一种方法 - 我构建了包含 ActiveModel::Model 的新模块,并使用新的验证方法进行了扩展。

    module ExtendedModel
      module ClassMethods
        def my_custom_validation_method(*args)
          # define validation here
        end
      end
    
      def self.included(base)
        base.class_eval do
          include ActiveModel::Model
          extend ClassMethods
        end
      end
    end
    

    然后我将这个新模块包含在我的表单类中

    class RegistrationForm
      include ExtendedModel
    
      my_custom_validation_method
      ...
    end
    

    当然,这个解决方案不是 100% 优雅的:

    1. 它要求我所有的扩展都必须添加到 ExtendedModel 模块。
    2. 从 ActiveRecord::Base 继承的模型必须是 单独提供这些额外的方法

    【讨论】:

    • 冷混合溶液。我同意这不是完美的解决方案,但我认为这是 ruby​​ 中最优雅的东西。但是,我想知道你什么时候需要这样的代码?通常我不需要 ruby​​ 中的全局作用域函数。仅针对特定的几个类或模块就足够了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    • 1970-01-01
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    相关资源
    最近更新 更多