I've got a custom EachValidator
that is used in two different models. I moved it to a Concern to DRY the models:
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
When running Rails (in this case via RSpec), I get this warning:
$ 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
Is there any way to avoid it and include the validator cleanly in each model?
Each time you include your Isbn
module it triggers included
method which opens IsbnValidator < ActiveModel::EachValidator
class and creates GOOD_ISBN
constant and validate_each
method inside of it. Note that these constant and method are created each time in the same class - IsbnValidator < ActiveModel::EachValidator
.
So, the first time you included Isbn
module you created GOOD_ISBN
constant inside IsbnValidator < ActiveModel::EachValidator
, after that you included Isbn
module into another class and included
method tried to create GOOD_ISBN
constant again in IsbnValidator < ActiveModel::EachValidator
and obviously failed with that error you got.
So instead your included
method should look like this:
module Isbn
extend ActiveSupport::Concern
included do
GOOD_ISBN = /^97[89]/.freeze
def validate_each(record, attribute, value)
# snip...
end
end
end
This way GOOD_ISBN
and validate_each
will be created for the classes you import Isbn
into (i.e. for Book
and BookPart
)