AngularJS validations with Rails model validations

After my previous post about AngularJS and Rails, I think the best topic to continue talking about is the form validations.

First of all we need to understand what a form validation does in AngularJS. 

In all fields in our form we need to define the attribute ng-model to tell to AngularJS our field’s identification, is a good practice to use the model’s name to handle all of yours :

<input type=“text” name=“name" ng-model="” />

AngularJS validates each input by many possible rules, for example, if you want to set an input as required you only need to set the attribute required:

<input type=“text” name=“name” required=“required” />

Finally our field is going to look more or less like this:

<input type=“text” name=“name” ng-model=“” required=“required” />

if a field has many  validations, we are going to have:

<input id=“contact_email” name=“contact[email]” ng-model=“” ng-pattern=“/[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}/i” required=“required” type=“text”>

Each ng- is an AngularJS directive, ng-model is to name the model and the other in this cases are to handle validations.

With all this we can set out submit button to only be enabled when all fields are valid:

<input name=“commit” ng-disabled=“form.$invalid” type=“submit” value=“Create”>

Now, with this info, we can work with our Rails integration. We’ll have a config file to set up the model’s we want to integrate.

1) First we define a file named afv.yml where we add the models to handle through AngularJS validation with this format:

   - Contact
   - Post

Here we define the env, and the models names. Each model needs a slash before the name and a space to get all as an Array.

2) This initializer load’s our config file, adds the necessary methods to our

module AngularValidation
  class << self
    attr_accessor :configuration
  def self.configure
    self.configuration ||=
  class Configuration
    attr_accessor :models, :ng_application_name, :ng_controller_name
    def initialize
      @models               = []
      @ng_application_name  = 'angularFormValidator'
      @ng_controller_name   = 'angularFormValidatorCntl'
afv_config_file = File.join(Rails.root,'config','angular_validation_models.yml')
afv_config = YAML.load_file(afv_config_file)[Rails.env].symbolize_keys
AngularValidation.configure do |config|
  config.models               = afv_config[:models]
  config.ng_application_name  = afv_config[:ng_application] if afv_config[:ng_application]
  config.ng_controller_name   = afv_config[:ng_controller]  if afv_config[:ng_controller]
module ModelValidators
  module ClassMethods
    def validations{|v|
          class: v.class.to_s.split('::').last,
          field_name: v.attributes.first,
          options: v.options
  def self.included(base)
afv_config[:models].each do |model|
  model.constantize.send :include, ModelValidators

3) We have some methods in our helper to use in our forms

def afv_javascript
    javascript_tag('angular.module("angularFormValidator", ["angularFormValidator.controllers"]);angular.module("angularFormValidator.controllers", []).controller("angularFormValidatorCntl", ["$scope", function($scope) {}]);')
  def afv_form_submit(model)
    {'ng-disabled' => "#{afv_form_name(model)}.$invalid"}
  def afv_form_name (model)
  def afv_field_validators(model, field_name)
    options = {'ng-model' => "#{model.to_s.downcase}.#{field_name.to_s}"}
    field_validations ={|i| i[:field_name]==field_name}
    field_validations.each do |validation|
      case validation[:class]
        when 'PresenceValidator' then
          options['required'] = 'required'
        when 'FormatValidator' then
          options['ng-pattern'] = "/#{validation[:options][:with].source}/i"
  def afv_validate_form?(model)
  def afv_ng_attributes(model)
    if afv_validate_form? model
        'ng-app' => AngularValidation.configuration.ng_application_name,
        'ng-controller' => AngularValidation.configuration.ng_controller_name
  • afv_javascript => this method puts a small javascript to define our application
    and a controller.
  • afv_form_submit     | add the attribute to submit button to enable/disable it.
  • afv_form_name       | builds the form name to connect with the validations
  • afv_field_validators  | converts rails validators info in fields attributes
  • afv_validate_form?  | checks if the model is configured to velidates with AngualrJS
  • afv_ng_attributes     | returns the ng-app and ng-controller for a form.

4) in our views we are going to call our helpers like this:

4.1) if we have a view for new, other for edit, etc. We are going to call our render line inside a content_tag to add the necessary attributes.

<%= content_tag :div, afv_ng_attributes(@contact.class) do %> <%= render ‘form’ %> <% end %>

Notice the @contact.class, this is to get the correct class for @contact, in this case our var it has an easy name to see what’s about, but if our var is @resource and the class is Contact, it’s easy to use @resource.class.

4.2) inside our form we need to do:

4.2.1) Adds the javascript for the app:

<%= afv_javascript %>

4.2.2) in our form definition we need to add the form name:

<%= form_for @contact, :html => {:name => afv_form_name(@contact.class)} do |f| %>

4.2.3) for each field we need to add the attributes to add angularjs verifications

<%= f.text_field :name, afv_field_validators(@contact.class, :name) %>

4.2.4) finally we need to add the form submit attributes:

<%= f.submit nil, afv_form_submit(@contact.class) %>

This is going to change our form to a code like this:

doss<div ng-app=“angularFormValidator” ng-controller=“angularFormValidatorCntl”>   <script> //<![CDATA[ angular.module(“angularFormValidator”, [“angularFormValidator.controllers”]);angular.module(“angularFormValidator.controllers”, []).controller(“angularFormValidatorCntl”, [“$scope”, function($scope) {}]); //]]> </script> <form accept-charset=“UTF-8” action=“/contacts” class=“new_contact” id=“new_contact” method=“post” name=“contact_form”><div style=“margin:0;padding:0;display:inline”><input name=“utf8” type=“hidden” value=“✓”><input name=“authenticity_token” type=“hidden” value=“3vjRTB1zLkRarvsfnD+zr78BHf2CAj+rfiTHGOhwUHQ=”></div>   <div class=“field”>     <label for=“contact_name”>Name</label><br>     <input id=“contact_name” name=“contact[name]” ng-model=“” required=“required” type=“text”>   </div>   <div class=“field”>     <label for=“contact_email”>Email</label><br>     <input id=“contact_email” name=“contact[email]” ng-model=“” ng-pattern=“/[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}/i” required=“required” type=“text”>   </div>   <div class=“field”>     <label for=“contact_message”>Message</label><br>     <textarea id=“contact_message” name=“contact[message]” ng-model=“contact.message”></textarea>   </div>   <div class=“actions”>     <input name=“commit” ng-disabled=“contact_form.$invalid” type=“submit” value=“Create Contact”>   </div> </form> </div>

I’m going to do a Gem with this , I’m finishing to put all kind of validators and searching for a way we shouldn’t need to add thing to the form syntax, etc For now, I think is a good point to understand how AngularJS works and use it with rails.

Example code:

Leave a Reply

Your email address will not be published.