У меня есть кастом 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
класс и создает GOOD_ISBN
константу и validate_each
метод внутри него. Обратите внимание, что эти константы и методы каждый раз создаются в одном и том же классе — IsbnValidator < ActiveModel::EachValidator
.
Итак, в первый раз, когда вы включили Isbn
модуль, вы создали GOOD_ISBN
константу внутри IsbnValidator < ActiveModel::EachValidator
, после этого вы включили Isbn
модуль в другой класс, а included
метод попытался снова создать GOOD_ISBN
константу в IsbnValidator < ActiveModel::EachValidator
и, очевидно, потерпел неудачу с той ошибкой, которую вы получили.
Поэтому вместо этого ваш метод included
должен выглядеть так:
module Isbn
extend ActiveSupport::Concern
included do
GOOD_ISBN = /^97[89]/.freeze
def validate_each(record, attribute, value)
# snip...
end
end
end
Таким образом, GOOD_ISBN
и validate_each
будут созданы для классов, в которые вы импортируете Isbn
(т.е. для Book
и BookPart
)