Как я могу загрузить собственный валидатор, который не наследуется напрямую от класса валидатора Rails в Rails 5? - PullRequest
0 голосов
/ 21 января 2019

Я писал несколько пользовательских валидаторов для проекта 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

Есть идеи?

1 Ответ

0 голосов
/ 21 января 2019

Я разобрался в проблеме. Строка self.abstract_class = true в RegexValidator тихо выдавала ошибку, потому что в классе нет метода self.abstract_class. Я думал, что это произошло потому, что видел это в классе ApplicationRecord, но теперь я понимаю, что это определено в классе ActiveRecord::Base.

Я определил это, добавив require_relative "../validators/email_validator" в начало файла user.rb. После этого я смог увидеть ошибку, которая молчала раньше:

/home/tomeraberbach/Desktop/msf/src/app/validators/regex_validator.rb:4:in `<class:RegexValidator>': undefined method `abstract_class=' for RegexValidator:Class (NoMethodError)

После удаления строки self.abstract_class = true и строки require_relative "../validators/email_validator" проблема была решена.

...