Я писал несколько пользовательских валидаторов для проекта Rails 5, над которым я работал. Например:
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if value.present? && !/\A[^\p{Z}]+@[^\p{Z}]+\.[^\p{Z}]+\z/.match?(value)
record.errors.add(attribute, "must be an email")
end
end
end
Этот подход работал нормально, но многие из моих пользовательских валидаторов также проверяли соответствие регулярному выражению, поэтому я решил создать абстрактный класс RegexValidator
:
class RegexValidator < ActiveModel::EachValidator
self.abstract_class = true
def regex
raise "Children of this class must implement the 'regex' method."
end
def message(record, attribute, value)
raise "Children of this class must implement the 'message(record, attribute, value)' method."
end
def validate_each(record, attribute, value)
if value.present? && !regex.match?(value)
record.errors.add(attribute, message(record, attribute, value))
end
end
end
Так что теперь EmailValidator
реализовано так:
class EmailValidator < RegexValidator
def regex
/\A[^\p{Z}]+@[^\p{Z}]+\.[^\p{Z}]+\z/
end
def message(record, attribute, value)
"must be an email"
end
end
Однако, так как это изменение Rails 5 больше не загружает мой EmailValidator
, даже если RegexValidator
и EmailValidator
помещены в файлы с соответствующими именами, regex_validator.rb
и email_validator.rb
, в папку app/validators
, которая была будучи загруженным ранее (это отличает этот вопрос от аналогичного вопроса ). Я подозреваю, что это потому, что EmailValidator
больше не наследуется напрямую от ActiveModel::EachValidator
, но это не должно иметь значения.
Для справки, при попытке создать файл миграции произошла следующая ошибка:
/var/lib/gems/2.5.0/gems/activemodel-5.2.2/lib/active_model/validations/validates.rb:121:in `rescue in block in validates': Unknown validator: 'EmailValidator' (ArgumentError)
from /var/lib/gems/2.5.0/gems/activemodel-5.2.2/lib/active_model/validations/validates.rb:118:in `block in validates'
from /var/lib/gems/2.5.0/gems/activemodel-5.2.2/lib/active_model/validations/validates.rb:114:in `each'
from /var/lib/gems/2.5.0/gems/activemodel-5.2.2/lib/active_model/validations/validates.rb:114:in `validates'
from /home/tomeraberbach/Desktop/msf/src/app/models/user.rb:7:in `<class:User>'
from /home/tomeraberbach/Desktop/msf/src/app/models/user.rb:4:in `<main>'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:50:in `load'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:50:in `load'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:476:in `block in load_file'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:661:in `new_constants_in'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:475:in `load_file'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:373:in `block in require_or_load'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:37:in `block in load_interlock'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies/interlock.rb:14:in `block in loading'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/concurrency/share_lock.rb:151:in `exclusive'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies/interlock.rb:13:in `loading'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:37:in `load_interlock'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:356:in `require_or_load'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:46:in `block in require_or_load'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:16:in `allow_bootsnap_retry'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:45:in `require_or_load'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:510:in `load_missing_constant'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:58:in `block in load_missing_constant'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:16:in `allow_bootsnap_retry'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:57:in `load_missing_constant'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:195:in `const_missing'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/inflector/methods.rb:283:in `const_get'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/inflector/methods.rb:283:in `block in constantize'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/inflector/methods.rb:281:in `each'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/inflector/methods.rb:281:in `inject'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/inflector/methods.rb:281:in `constantize'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:582:in `get'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:613:in `constantize'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise.rb:316:in `get'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise/mapping.rb:83:in `to'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise/mapping.rb:78:in `modules'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise/mapping.rb:95:in `routes'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise/mapping.rb:162:in `default_used_route'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise/mapping.rb:72:in `initialize'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise.rb:346:in `new'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise.rb:346:in `add_mapping'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise/rails/routes.rb:243:in `block in devise_for'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise/rails/routes.rb:242:in `each'
from /var/lib/gems/2.5.0/gems/devise-4.5.0/lib/devise/rails/routes.rb:242:in `devise_for'
from /home/tomeraberbach/Desktop/msf/src/config/routes.rb:3:in `block (2 levels) in <main>'
from /var/lib/gems/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/routing/mapper.rb:879:in `scope'
from /home/tomeraberbach/Desktop/msf/src/config/routes.rb:2:in `block in <main>'
from /var/lib/gems/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/routing/route_set.rb:432:in `instance_exec'
from /var/lib/gems/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/routing/route_set.rb:432:in `eval_block'
from /var/lib/gems/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/routing/route_set.rb:414:in `draw'
from /home/tomeraberbach/Desktop/msf/src/config/routes.rb:1:in `<main>'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:50:in `load'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:50:in `load'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:285:in `block in load'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:257:in `load_dependency'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:285:in `load'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/application/routes_reloader.rb:41:in `block in load_paths'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/application/routes_reloader.rb:41:in `each'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/application/routes_reloader.rb:41:in `load_paths'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/application/routes_reloader.rb:20:in `reload!'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/application/routes_reloader.rb:30:in `block in updater'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/file_update_checker.rb:83:in `execute'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/application/routes_reloader.rb:10:in `execute'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/application/finisher.rb:130:in `block in <module:Finisher>'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/initializable.rb:32:in `instance_exec'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/initializable.rb:32:in `run'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/initializable.rb:61:in `block in run_initializers'
from /usr/lib/ruby/2.5.0/tsort.rb:228:in `block in tsort_each'
from /usr/lib/ruby/2.5.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
from /usr/lib/ruby/2.5.0/tsort.rb:431:in `each_strongly_connected_component_from'
from /usr/lib/ruby/2.5.0/tsort.rb:349:in `block in each_strongly_connected_component'
from /usr/lib/ruby/2.5.0/tsort.rb:347:in `each'
from /usr/lib/ruby/2.5.0/tsort.rb:347:in `call'
from /usr/lib/ruby/2.5.0/tsort.rb:347:in `each_strongly_connected_component'
from /usr/lib/ruby/2.5.0/tsort.rb:226:in `tsort_each'
from /usr/lib/ruby/2.5.0/tsort.rb:205:in `tsort_each'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/initializable.rb:60:in `run_initializers'
from /var/lib/gems/2.5.0/gems/railties-5.2.2/lib/rails/application.rb:361:in `initialize!'
from /home/tomeraberbach/Desktop/msf/src/config/environment.rb:5:in `<main>'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:20:in `require_with_bootsnap_lfi'
from /var/lib/gems/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:29:in `require'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:291:in `block in require'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:257:in `load_dependency'
from /var/lib/gems/2.5.0/gems/activesupport-5.2.2/lib/active_support/dependencies.rb:291:in `require'
from /var/lib/gems/2.5.0/gems/spring-2.0.2/lib/spring/application.rb:102:in `preload'
from /var/lib/gems/2.5.0/gems/spring-2.0.2/lib/spring/application.rb:153:in `serve'
from /var/lib/gems/2.5.0/gems/spring-2.0.2/lib/spring/application.rb:141:in `block in run'
from /var/lib/gems/2.5.0/gems/spring-2.0.2/lib/spring/application.rb:135:in `loop'
from /var/lib/gems/2.5.0/gems/spring-2.0.2/lib/spring/application.rb:135:in `run'
from /var/lib/gems/2.5.0/gems/spring-2.0.2/lib/spring/application/boot.rb:19:in `<top (required)>'
from /usr/local/lib/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'
from /usr/local/lib/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'
from -e:1:in `<main>'
Мой User
класс:
##
# A class representing a user account for this web application
# Instances of this class represent rows in the +users+ table on the database.
class User < ApplicationRecord
# Validation
validates_presence_of :email, :encrypted_password
validates :email, email: true
# Associations
devise :database_authenticatable, :registerable, :recoverable,
:rememberable, :trackable, :validatable
has_and_belongs_to_many :roles
# Events
before_validation do
# Removes unnecessary whitespace
self.email = email.strip
end
end
Есть идеи?