28

I am trying to add an email custom validators for my app; However, where should I place the custom validator? (I really do not want to place this validator class inside the model) Is there a cli generator for validator?

http://guides.rubyonrails.org/active_record_validations.html

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      record.errors[attribute] << (options[:message] || "is not an email")
    end
  end
end

class Person < ApplicationRecord
  validates :email, presence: true, email: true
end

What's the convention location/path for custom validator?

devoh
  • 867
  • 9
  • 13
XY L
  • 25,431
  • 14
  • 84
  • 143

4 Answers4

38

I put them in /app/validators/email_validator.rb and the validator will be loaded automatically.

Also, I don't know if it's your case but you should replace this in your form. If so, a first validation is made before the user reach your controller.

  <div class="field">
    <%= f.label :email %>
    <%= f.text_field :email, required: true %>
  </div>

By :

  <div class="field">
    <%= f.label :email %>
    <%= f.email_field :email, required: true %>
  </div>
devoh
  • 867
  • 9
  • 13
  • is that the convention in rails? and will it be auto loaded? – XY L Feb 15 '17 at 15:07
  • 1
    Apparently [SO:5263239](http://stackoverflow.com/questions/5263239/where-should-rails-3-custom-validators-be-stored),[SO:35953656](http://stackoverflow.com/questions/35953656/where-exactly-do-i-put-autoload-path-for-custom-validator-in-config-application) – devoh Feb 15 '17 at 15:09
  • Thanks for the additional info. I am using api only rails. :D – XY L Feb 15 '17 at 15:23
  • 4
    If you are using spring you have to restart it in order to load the new path – Dobromir Minchev May 16 '18 at 03:37
  • 4
    `spring stop` was necessary for me in Rails 5.2, otherwise it wasn't picked up. – Jack Kinsella Nov 01 '18 at 11:57
  • In Rails 5 applications the validator should be in the app/lib folder because all code inside the app folder is autoloaded in dev and eager loaded in prod. And most importantly it is autoreloaded in development so you don't have to restart server each time you make changes. So in Rails 5 applications the validator should be in `app/validators/email_validator.rb` – Chilian Jan 28 '20 at 12:55
4

Rails 6

app/models/validators/ is also a sensible directory to house validators.

I choose this directory over others such as app/validators since the validators are context-specific to ActiveModel

app/models/person.rb

class Person < ApplicationRecord
  validates_with PersonValidator
end

app/models/validators/person_validator.rb

class PersonValidator < ActiveModel::Validator
  def validate(record)
    record.errors.add(:name, 'is required') unless record.name
  end
end

config/application.rb

module ...
  class Application < Rails::Application
    config.load_defaults 6.1

    config.autoload_paths += Dir[File.join(Rails.root, 'app', 'models', 'validators')]
  end
end

Specs for the validators would be placed in spec/models/validators/

ddavison
  • 28,221
  • 15
  • 85
  • 110
  • Note - if you design your rails app with other subdirectories, you can use `**` to also encapsulate those. `Dir[File.join(Rails.root, 'app', 'models', '**', 'validators')]` – ddavison Jan 28 '22 at 18:23
1

My validator did not loaded automatically. At least is not showing when I type in the console:

> ActiveSupport::Dependencies.autoload_paths

So, I put in my config/application.rb, this line:

config.autoload_paths += %W["#{config.root}/lib/validators/"]
Cleber Reizen
  • 420
  • 4
  • 11
  • 3
    `lib/` folders are not autoloaded. They removed lib autoload from rails 5. You should create this folder and place validators there. `app/validators/` Then they will be autoloaded, so you don't need to make any setup in config.autoload_paths. – zhisme Feb 20 '18 at 08:05
-3

In rails 6 I had to put them in /app/models/concerns for them to autoload