This is a step by step guide for Server Side form validations with AngularJS and Rails backend

Most of the information comes from the following article but I add some important information that was left out:

Server Form Validation with Angular.js

We will start with the form:


<form name="yourForm" ng-submit="addPost()" novalidate>
  <input type="text" name="title" ng-model="newPost.title" server-error />
  <!--take note the name attribute must be the exact same as the attribute name in your rails model -->
  <span class="errors" ng-show="yourForm.title.$dirty && yourForm.title.$invalid">
    <span ng-show="yourForm.title.$error.server">{{errors.title}}</span>
  </span>

  <input type="text" name="content" ng-model="newPost.content" server-error />
  <span class="errors" ng-show="yourForm.content.$dirty && yourForm.content.$invalid">
    <span ng-show="yourForm.content.$error.server">{{errors.content}}</span>
  </span>

  <input type="submit" />

</form>

The "novalidate" turns off the in-browser HTML5 validations which we dont want for Angular and the "server-error" makes a call to our directive that we will be making next.

Next we will create the directive that waits for input change then invalidates the server error until submission again:


angular.module('yourApp').directive('serverError', function(){
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope,element,attrs,ctrl){
      return element.on('change keyup', function(){
        return scope.$apply(function(){
          return ctrl.$setValidity('server', true);
        });
      });
    }
  };
});

Now we will add the functionality to your controller:


angular.module('yourApp').controller('PostCtrl', function($scope, PostService) {
  $scope.addPost = function() {
var error, success, newPost; newPost = $scope.newPost; $scope.errors = {}; //clean up previous server errors success = function(result) { //things to do if it returns success, here is my example code, will likely be different for you $scope.posts.unshift(result); $scope.newPost = {}; }; error = function(result) { angular.forEach(result.data.errors, function(errors, field) { $scope.yourForm[field].$setValidity('server', false); $scope.errors[field] = errors.join(', '); }); }; // if you are using $http in your server do this // return PostService.create(post).then(success, error); // otherwise if you are using $resource in your service do this // return PostService.save(post).$promise.then(success, error); }; });

Lastly we will change your models Rails Controller so that it returns the errors as json:


module Api
  module V1
    class PhrasesController < ApplicationController
      respond_to :json

      #other code.....

      def create
        @phrase = Phrase.new(phrase_params)
        @phrase.save
        respond_with @phrase, location: "" #this is the part where is returns the success or returns errors with the response
      end
      
      def create
        @phrase = Phrase.find(params[:id])
        @phrase.update(phrase_params)
        respond_with @phrase, location: "" #this is the part where is returns the success or returns errors with the response
      end
      
      #more code.....   
    end
  end
end

Basically this is what respond_with does automatically


if @phrase.save
  render json: @phrase, status: 200
else
  render json: {errors: @phrase.errors}, status: 422
end

You now have server side validation! Congrats!