Rails 4 - 关于通用验证的问题

时间:2014-03-31 20:01:43

标签: ruby-on-rails validation activesupport-concern

我刚遇到Rails问题,我想用它们来验证我的模型。但我希望验证是通用的,因此仅当我包含我关注的类具有该属性时才使用验证。我认为这很容易,但我尝试了很多方法,比如使用column_names,constantize,send等等但没有任何作用。做正确的方法是什么?代码:

module CommonValidator
  extend ActiveSupport::Concern

  included do
    validates :email, presence: { message: I18n.t(:"validations.commons.email_missing") }, 
                      format: { with: /\A[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\z/i, 
                      message: I18n.t(:"validations.commons.email_wrong_format"), 
                            allow_blank: true } if self.column_names.include? :email
  end
end

class Restaurant < ActiveRecord::Base
  include CommonValidator
  .
  .
  .
end

餐厅当然有一个电子邮件属性。是否有可能检查包含我关注的类中是否存在属性?我希望将我的CommonValidations包含在许多不具有电子邮件属性的模型中。我正在使用rails 4。

2 个答案:

答案 0 :(得分:1)

您可以在当前实例上使用respond_to?,如下所示:

validates :email, presence: { message: I18n.t(:"validations.commons.email_missing") }, 
                  format: { with: /\A[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\z/i, 
                  message: I18n.t(:"validations.commons.email_wrong_format"), 
                  allow_blank: true }, 
                  if: lambda { |o| o.respond_to?(:email) }

@ coreyward建议的另一个选项是定义一个扩展EachValidator的类。例如,对于电子邮件验证:

# app/validators/email_validator.rb
class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
      record.errors[attribute] << (options[:message] || I18n.t(:"validations.commons.email_wrong_format"))
    end
  end
end

然后您可以将验证调用更新为:

validates :email, 
          presence: { message: I18n.t(:"validations.commons.email_missing") },
          email: true, 
          allow_blank: true

答案 1 :(得分:1)

我正在寻找类似的东西,但有自定义验证。 我最终得到了一些我认为可以分享的东西,包括通用测试。

首先,设置问题app/models/concern/my_concern.rb

请注意,我们不会将validate_my_field定义为ClassMethods模块。

module MyConcern
  extend ActiveSupport::Concern

  included do
    validate :my_field, :validate_my_field
  end

private

  def validate_my_field
    ...
  end

end

将问题纳入您的模型app/models/my_model.rb

class MyModel < ActiveRecord::Base
  include MyConcern
end

加载spec/support/rails_helper中的共享示例:

…
  Dir[Rails.root.join('spec/concerns/**/*.rb')].each { |f| require f }
…

创建关注共享示例spec/concerns/models/my_field_concern_spec.rb

RSpec.shared_examples_for 'my_field_concern' do
  let(:model) { described_class } # the class that includes the concern

  it 'has a valid my_field' do
    instance = create(model.to_s.underscore.to_sym, my_field: …)
    expect(instance).not_to be_valid
    …
  end
end

然后最后将共享示例调用到您的模型规范spec/models/my_model_spec.rb

require 'rails_helper'

RSpec.describe MyModel do
  include_examples 'my_field_concern'

  it_behaves_like 'my_field_concern'
end

我希望这可以提供帮助。