1

我刚刚遇到了 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。

4

2 回答 2

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
于 2014-03-31T20:11:52.803 回答
1

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

首先,设置关注点app/models/concern/my_concern.rb

请注意,我们没有将 in 定义validate_my_fieldClassMethods模块。

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

我希望这会有所帮助。

于 2017-03-17T09:16:05.750 回答