In order to protect your application from the invalid input on server side we can easily use validations. Imagine you have a model
Product where the attributes name, description and price should not be empty, and price should have a specific format and range.
Most probably, in our model we will set something like:
class Product < ActiveRecord::Base
attr_accessible :description, :name, :price
validates_presence_of :name, :description, :price
validates :price, :format => { :with => /^\d{0,8}\.\d{0,2}$/ }, :numericality => {:greater_than_or_equal_to => 0.01, :less_than_or_equal_to => 100.00}
end
Whenever user tries to add a new product, the form will be sent to the server and the returned response will contain object errors. What if we want to save server’s time and do the validations on the client side? Well, wether we can write some javascript ourselves or we can use client_side_validations gem.
The installation of the gem is very simple. Just follow the steps from their documentation.

Now when we installed and add the “//= require rails.validations” to our application.js, it is pretty easy to use- we just add “validation: true” to our form and we have it done!
Still, let’s see some more specific cases.
Use symbols to build form- not strings!
Very simple, our form will be built “the same” way wether we use:
<%= f.label :description %><br />
<%= f.text_field :description %>
or:
<%= f.label 'description' %><br />
<%= f.text_field 'description' %>
This is not the same for form builder, why?
Remember what is the main difference between symbol and a string, string is mutable and symbol is not. What does it mean? String changes its object_id during time while symbol remains always with the same object_id. That is why. Have this in mind because you might waste some precious time debugging it! You can find more details about it on stack overflow.
Custom validations errors preview
Imagine you don’t want that after error another label is rendered. You want a paragraph. In initializers/client_side_validations.rb uncomment the following part and replace <label> with <p>
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
unless html_tag =~ /^<p/
%{<div class="field_with_errors">#{html_tag}<p for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</p></div>}.html_safe
else
%{<div class="field_with_errors">#{html_tag}</div>}.html_safe
end
end
And override the default behavior by creating new javascript file ../javascripts/rails.validations.actionView.js (do not forget to add it in your application.js):
$(document).ready(function (){
window.ClientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'] = {
add: function(element, settings, message) {
var form, inputErrorField, label, labelErrorField;
form = $(element[0].form);
if (element.data('valid') !== false && !(form.find("p.message[for='" + (element.attr('id')) + "']")[0] != null)) {
inputErrorField = jQuery(settings.input_tag);
labelErrorField = jQuery(settings.label_tag);
label = form.find("p[for='" + (element.attr('id')) + "']:not(.message)");
element.before(inputErrorField);
inputErrorField.find('span#input_tag').replaceWith(element);
inputErrorField.find('p.message').attr('for', element.attr('id'));
labelErrorField.find('p.message').attr('for', element.attr('id'));
labelErrorField.insertAfter(label);
labelErrorField.find('p#label_tag').replaceWith(label);
}
return form.find("p.message[for='" + (element.attr('id')) + "']").text(message);
},
remove: function(element, settings) {
var errorFieldClass, form, inputErrorField, label, labelErrorField;
form = $(element[0].form);
errorFieldClass = jQuery(settings.input_tag).attr('class');
inputErrorField = element.closest("." + (errorFieldClass.replace(" ", ".")));
label = form.find("p[for='" + (element.attr('id')) + "']:not(.message)");
labelErrorField = label.closest("." + errorFieldClass);
if (inputErrorField[0]) {
inputErrorField.find("#" + (element.attr('id'))).detach();
inputErrorField.replaceWith(element);
label.detach();
return labelErrorField.replaceWith(label);
}
}
}
});
And this is it, now instead of label we will have a paragraph element.
Custom validations methods
Imagine we want a special format for the product name, and we will need the same format for other fields in application, the best is tu create our own custom validator. How to do that? Create app/validators/name_validator.rb and use something like:
class NameValidator < ActiveModel::EachValidator
def validate_each(record, attr_name, value)
unless value =~ /(CODE|TEST)-\w/
record.errors.add(attr_name, :name, options.merge(:value => value))
end
end
end
module ActiveModel::Validations::HelperMethods
def validates_name(*attr_names)
validates_with NameValidator, _merge_attributes(attr_names)
end
end
Customize the error message in yml file:
en:
errors:
messages:
name: "This is not exactly what I want, try harder! It has to start with CODE- or TEST- and it contains only letters"
And bind the validation on ClientSideValidations.validator. In ../javascripts/rails.validations.customValidators.js
$(document).ready(function (){
window.ClientSideValidations.validators.local['name'] = function(element, options) {
if (!/(CODE|TEST)-\w/.test(element.val())) {
return options.message;
}
}
});
And final step, use it:
class Product < ActiveRecord::Base
NameValidator
ActiveModel::Validations::HelperMethods
attr_accessible :description, :name, :price
validates_presence_of :name, :description, :price
validates :price, :format => { :with => /^\d{0,8}\.\d{0,2}$/ }, :numericality => {:greater_than_or_equal_to => 0.01, :less_than_or_equal_to => 100.00}
validates_name :name
end
Here you go! Custom name validation is done!
For more ways of using this handsome plugin check their documentation.
This project is also available on my Github account, check here, commit: 3b9fcaacbe87755293648719e19c9b71202e0072.
Happy coding!