Rails where to place your Activemodel::validators

activemodel, ruby-on-rails, validation

Solution

You do not need include ActiveModel::Validations

My preference to to keep the validation objects in the model folder.

So for model Gender you have a file gender.rb

For the validator GenderValidator you have the file gender_validator.rb

So both files site together in the model folder.

Here is a validator for my Newsletter model

class NewsletterValidator < ActiveModel::Validator
  def validate(record)
      if record.send_test_email
        if test_email_address.blank?
          record.errors[:test_email_address] << "Test email address is blank"
        end
        if record.send_email_to_subscribers
          record.errors[:send_test_email] << "You cannot send a test and send to subscribers at the same time"
        end
      end

  end
end

In my Newsletter model I simply have

  validates_with NewsletterValidator

You have a spelling mistake in your example

You have

class GenderValidator < ActiveModel::validator

It should be

class GenderValidator < ActiveModel::Validator

Note the capital V

Problem

This is a two part question. Part one if my Model that i am writing the validations for is inhering from `ActiveRecord::Base` do i need to `include ActiveModel::Validations` within that class?? the API for rails doesnt say but here in yehudakatz blog seems to hint that? part two is where would be the best place to put these validator files? under helpers or as a new model or in lib? my current validator looks like this ``` class GenderValidator < ActiveModel::validator def validate(record) cred = /(\d{6})(\d{4})(\d{1})(\d{2})/.match(record.id_number.to_s) #breaks up the id into the relevent sections namely birthdate, gender, nationality, validator. unless cred[0][/\d{13}/] #checks to see if the id is a valid length of numbers if it isnt then skip the validation of gender return true else birthdate = cred[1] #returns a 6 digit string 'yymmdd' parsed_gender = cred[2] #returns a 4 digit string '0001-4999:female 5000-9999:male' nationality = cred[3] # should return either a 1 or a 0 1 if the person is foreign or 0 if the person is southafrican validate_gender(parsed_gender, record) end end private def validate_gender(parsed_gender, record) calculate_gender = (parsed_gender <= 4999 ? :female : :male) unless employee.gender == calculate_gender employee.errors[:gender] << "Your id indicates you have entered the wrong gender" end end end ``` an valid id number of each person is optional, but if they do specify it it should check to see if the gender is correct. if i keep it in the same model the employees model then i get this error ``` ActionController::RoutingError (uninitialized constant Employee::GenderValidator): app/models/employee.rb:25:in `<class:Employee>' app/models/employee.rb:1:in `<top (required)>' lib/role_requirement_system.rb:19:in `inherited' app/controllers/employees_controller.rb:1:in `<top (required)>' librato-rails (0.8.1) lib/librato/rack/middleware.rb:12:in `call' ``` so i take it they cant be in the same file. what is the best practice for validations? i watched all the rails casts and i have read a few blogs and i am quite new still. EDIT in my model i include this class like ``` include ActiveModel::Validations ``` and my validations look like this ``` validates_presence_of :name, :position, :gender validate :instance_validations, :on => :create def instance_validations validates_with GenderValidator end ``` just incase you wanted to see that too thanks ahead!

Original source