【问题标题】:ActiveModel::Validations on anonymous class匿名类上的 ActiveModel::Validations
【发布时间】:2013-01-21 02:29:39
【问题描述】:

我正在开发一个类似于 DataMapper 的小型 ODM 项目,并且正在尝试使用 ActiveModel::Validations 组件。但是,我在编写测试时遇到了一个问题——我使用匿名类来构建我的测试模式,但是在运行验证器时,ActiveModel::Name 类抛出了一个错误: Class name cannot be blank. You need to supply a name argument when anonymous class given

这里有一个简单的代码示例来重现:

require 'active_model'

book_class = Class.new do
  include ActiveModel::Validations

  validates_presence_of :title

  def title; ""; end # This will fail validation
end

book_class.new.valid? # => throws error

只有在验证器失败时才会引发异常 - 我猜当它尝试构建验证错误消息时会发生问题。所以我的问题是:

  • 我进行了大量搜索,但找不到任何人试图做类似的事情。这对 ActiveModel 来说是不可能的,还是有我不知道的解决方法?

【问题讨论】:

    标签: ruby activemodel


    【解决方案1】:

    ActiveModel 在设置错误消息时尝试获取模型名称(如您在此处看到的)。解决它的最快方法(不给匿名类一个名称)是给你的类一个类方法model_name,它返回一个ActiveModel::Name 的实例。

    例如

    require 'active_model'
    
    book_class = Class.new do
      include ActiveModel::Validations
      def self.model_name
        ActiveModel::Name.new(self, nil, "temp")
      end
      validates_presence_of :title
    
      def title; ""; end # This will fail validation
    end
    
    book_class.new.valid? # => no error
    

    【讨论】:

    • 谢谢,正是我想要的!我注意到ActiveModel::Name 可以将类名作为参数,但没有发现我可以通过self.model_name 返回我自己的实例。另一个不在深夜编程的原因......:P
    • 为什么返回 ActiveModel::Name 的实例而不是来自 .model_name 的纯字符串?
    • 这是 2 年前的事了,但是 IIRC,验证过程需要(预期?)来自该方法的 ActiveModel::Name 实例。
    【解决方案2】:

    ActiveModel::Namehere的初始化函数抛出错误。

    module ActiveModel
      class Name
        def initialize(klass, namespace = nil, name = nil)
          @name = name || klass.name
    
          raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if @name.blank?       
          # ...
        end
      end
    end
    

    因此,与其定义返回ActiveModel::Name 的类方法model_name,不如定义返回String 的类方法name

    require 'active_model'
    
    book_class = Class.new do
      include ActiveModel::Validations
      validates_presence_of :title
    
      def self.name
        "Book"
      end
    
      def title; ""; end # This will fail validation
    end
    
    book_class.new.valid? # => false
    

    【讨论】:

    • 这本质上是因为Class.new.name #=> nil,所以要么将name 传递给ActiveModel::Name,要么在类上定义一个name 方法。
    猜你喜欢
    • 2020-02-12
    • 1970-01-01
    • 2014-03-20
    • 2016-10-02
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多