Skip to content
bcardarella edited this page Mar 27, 2011 · 38 revisions

Custom Validators

Client Side Validations supports the use of custom validators in Rails 3. The following is an example for creating a custom validator that validates the format of email addresses.

Let's say you have several models that all have email fields and you are validating the format of that email address on each one. This is a common validation and could probably benefit from a custom validator. We're going to put the validator into config/initializers/email_validator.rb

# config/initializers/email_validator.rb
class EmailValidator < ActiveModel::EachValidator
  def validates_each(record, attr_name, value)
    unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
      record.errors.add(attr_name, :email, options.merge(:value => value))
    end
  end
end

# This allows us to assign the validator in the model
module ActiveModel::Validations::HelperMethods
  def validates_email(*attr_names)
    validates_with EmailValidator, _merge_attributes(attr_names)
  end
end

Next we need to add the error message to the Rails i18n file config/locales/en.yml

# config/locales/en.yml
en:
  errors:
    messages:
      email: "Not an email address"

Finally we need to add a client side validator. This can be done by hooking into the clientSideValidations.validator object. Create a new file public/javascripts/rails.validations.custom.js

// public/javascripts/rails.validations.custom.js
// Note: this style of how to write the custom validators for the client side will likely change over time.
// Refer back to this wiki in the future.

// The validator variable is a JSON Object
// The selector variable is a jQuery Object
clientSideValidations.validators.local['email'] = function(validator, element) {
  // Your validator code goes in here
  if (!/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i.test(element.val())) {
    // When the value fails to pass validation you need to return the error message.
    // It can be derived from validator.message
    return validator.message;
  }
}

Don't forget to include your new javscript file

<%= javascript_include_tag 'jquery', 'rails.validations', 'rails.validations.custom' -%>

That's it! Now you can use the custom validator as you would any other validator in your model

# app/models/person.rb
class Person < ActiveRecord::Base
  validates_email :email
end

Client Side Validations will apply the new validator and validate your forms as needed.

Remote Validators

If you are creating a remote validator the Ajax should be non-async and you need to add the validator name to clientSideValidations.validators.remote instead of clientSideValidations.validators.local