在 Rails 中包含来自关注点的验证器 class

Including a Validator class from a Concern in Rails

我有一个自定义 EachValidator 用于两个不同的模型。我将其移至关注以干燥模型:

module Isbn
  extend ActiveSupport::Concern

  included do
    class IsbnValidator < ActiveModel::EachValidator
      GOOD_ISBN = /^97[89]/.freeze

      def validate_each(record, attribute, value)
       # snip...
      end
    end
  end
end
class Book < ApplicationRecord
  include Isbn

  validates :isbn, allow_nil: true, isbn: true
end
class BookPart < ApplicationRecord
  include Isbn

  validates :isbn, allow_nil: true, isbn: true
end

当 运行 Rails 时(在这种情况下通过 RSpec),我收到此警告:

$ bundle exec rspec
C:/Users/USER/api/app/models/concerns/isbn.rb:16: warning: already initialized constant Isbn::IsbnValidator::GOOD_ISBN
C:/Users/USER/api/app/models/concerns/isbn.rb:16: warning: previous definition of GOOD_ISBN was here

有没有办法避免它并在每个模型中干净地包含验证器?

每次包含 Isbn 模块时,它都会触发 included 方法,该方法会打开 IsbnValidator < ActiveModel::EachValidator class 并创建 GOOD_ISBN 常量和 validate_each里面的方法。请注意,这些常量和方法每次都在相同的 class - IsbnValidator < ActiveModel::EachValidator.

中创建

因此,第一次包含 Isbn 模块时,您在 IsbnValidator < ActiveModel::EachValidator 中创建了 GOOD_ISBN 常量,之后您将 Isbn 模块包含到另一个 class并且 included 方法试图在 IsbnValidator < ActiveModel::EachValidator 中再次创建 GOOD_ISBN 常量,但显然因您遇到的错误而失败。

所以您的 included 方法应该如下所示:

module Isbn
  extend ActiveSupport::Concern

  included do
    GOOD_ISBN = /^97[89]/.freeze

    def validate_each(record, attribute, value)
     # snip...
    end
  end
end

这样 GOOD_ISBNvalidate_each 将为您导入 Isbn 的 classes 创建(即 BookBookPart)