legendary_rob
legendary_rob

Reputation: 13012

Rails where to place your Activemodel::validators

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!

Upvotes: 3

Views: 1603

Answers (1)

Mark Stratmann
Mark Stratmann

Reputation: 1612

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

Upvotes: 8

Related Questions