有些模型会引发ArgumentError:Unknown validator,其他模型会找到验证器

时间:2016-06-02 05:39:11

标签: ruby-on-rails rspec

我在自定义属性验证程序中遇到了一个奇怪的错误。我有以下设置,一切都按预期工作(每个类都包含模块API和V1):

# app/models/api/v1/business_account.rb
class BusinessAccount
  has_many :transactions, class_name: BusinessAccountThings::Transaction
end

# app/models/api/v1/business_account_things/transaction.rb
module BusinessAccountThings
  class Transaction
    belongs_to :business_account
    validates :amount, money: true
  end
end

# app/validators/api/v1/money_validator.rb

class MoneyValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless /^\d+\.*\d{0,2}$/ =~ value.to_s
      record.errors[attribute] << 'Only two digits are allowed.'
    end
  end
end

我现在想在BusinessAccount中使用自定义验证器,如下所示:

class BusinessAccount
  has_many :transactions
  validates :current_balance, money: true
end

我在运行BusinessAccount的规范时遇到以下错误(尝试从Rails控制台加载类时出现类似错误):

/home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activemodel-4.2.4/lib/active_model/validations/validates.rb:120:in `rescue in block in validates': Unknown validator: 'MoneyValidator' (ArgumentError)
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activemodel-4.2.4/lib/active_model/validations/validates.rb:117:in `block in validates'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activemodel-4.2.4/lib/active_model/validations/validates.rb:113:in `each'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activemodel-4.2.4/lib/active_model/validations/validates.rb:113:in `validates'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account_things/transaction.rb:22:in `<class:Transaction>'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account_things/transaction.rb:5:in `<module:BusinessAccountThings>'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account_things/transaction.rb:3:in `<module:V1>'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account_things/transaction.rb:2:in `<module:API>'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account_things/transaction.rb:1:in `<top (required)>'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `block in require'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:360:in `require_or_load'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:494:in `load_missing_constant'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:184:in `const_missing'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account.rb:16:in `<class:BusinessAccount>'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account.rb:4:in `<module:V1>'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account.rb:2:in `<module:API>'
    from /home/hannes/workspaces/rails-app/app/models/api/v1/business_account.rb:1:in `<top (required)>'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `block in require'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:360:in `require_or_load'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:494:in `load_missing_constant'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:184:in `const_missing'
    from /home/hannes/workspaces/rails-app/spec/models/api/v1/business_account_spec.rb:5:in `<top (required)>'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1361:in `load'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1361:in `block in load_spec_files'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1359:in `each'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/lib/rspec/core/configuration.rb:1359:in `load_spec_files'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:106:in `setup'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:92:in `run'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:78:in `run'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/lib/rspec/core/runner.rb:45:in `invoke'
    from /home/hannes/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/rspec-core-3.4.4/exe/rspec:4:in `<top (required)>'
    from /home/hannes/.rbenv/versions/2.2.5/bin/rspec:23:in `load'
    from /home/hannes/.rbenv/versions/2.2.5/bin/rspec:23:in `<main>'

BusinessAccount中的第16行是has_many :transactions, class_name: BusinessAccountThings::Transaction, dependent: :destroy

Transaction中的第22行是validates :amount, money: true

如果我从Transaction删除第22行,问题就会消失。

如果我运行Transaction的规范,我会收到此错误:

1) API::V1::BusinessAccountThings::Transaction 
   Failure/Error:
     validates :current_balance,
               numericality: { greater_than_or_equal_to: 0 },
               money: true

 ArgumentError:
   Unknown validator: 'MoneyValidator'
 # ./app/models/api/v1/business_account.rb:9:in `<class:BusinessAccount>'
 # ./app/models/api/v1/business_account.rb:4:in `<module:V1>'
 # ./app/models/api/v1/business_account.rb:2:in `<module:API>'
 # ./app/models/api/v1/business_account.rb:1:in `<top (required)>'
 # ./spec/models/api/v1/business_account_things/transaction_spec.rb:5:in `block (2 levels) in <top (required)>'
 # ./spec/models/api/v1/business_account_things/transaction_spec.rb:7:in `block (2 levels) in <top (required)>'
 # ------------------
 # --- Caused by: ---
 # NameError:
 #   uninitialized constant API::V1::BusinessAccount::MoneyValidator
 #   ./app/models/api/v1/business_account.rb:9:in `<class:BusinessAccount>'

所以看起来两个类似乎无法同时加载MoneyValidator ...我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

自动加载API::V1::MoneyValidator因设置失败。

business_account.rb正在尝试将其加载为API::V1::BusinessAccount::MoneyValidator。这会失败,因为它在API::V1下命名,而不是API::V1::BusinessAccount

自动加载还会尝试查找MoneyValidator(没有命名空间;如源代码中所写)。因此,如果您将验证器类移出API::V1命名空间并使其成为顶级常量,那么它应该可以工作。