AngularJS - $http POST with Rails 3.2.3

I'm building a simple Contact Management app with Crud using AngularJS 1.0.0rc8.

Getting a list of currently existing contacts is no problem, but while attempting to save a new Contact to the server, a new row is created - complete with the correct id, created_at, and updated_at values - but the rest of the models data is ignored.

Here is a screenshot to show what I mean:

enter image description here

As you can see, numbers 4 and 5 were given the Id's but first_name, last_name, and phone_num were not saved to the database.

I am using a $scope.addContact function within the Controller that deals with the object.

Here is the entire code for the Contact List Controller:

'use strict';

function ContactListCtrl($scope, $http) {
  $http.get('/contacts').success(function(data) {
    $scope.contacts = data;
  });    

  $scope.addContact = function(data) {      

    $http.post('/contacts/', data).success(function(data) {
        console.log(data);
        data.first_name = $("#new_contact_first_name").val();
        data.last_name = $("#new_contact_last_name").val();
    });

    this.newFirstName = '';
    this.newLastName = '';
  };

};

After clicking 'Save' on the new-contact.html partial, the Object is logged to the Console, if I inspect its contents, than sure enough the values are collected - notice Jimi Hendrix is there:

enter image description here

Here is the form as it appears in the new-contact.html template:

<form id="contact_form" ng-submit="addContact()">
            <input type="text" id="new_contact_first_name" name="newContactFirstName" ng-model="newFirstName" placeholder="First Name"></br>
            <input type="text" id="new_contact_last_name" name="newContactLastName" ng-model="newLastName" placeholder="Last Name"></br>
            <input type="button" id="contact_submit_btn" value="Add Contact" class="btn btn-primary">               
        </form>

The addContact() function is fired after the form is submitted with JQuery:

$(document).ready(function(){       

        $("#contact_submit_btn").click(function(){          
            $("#contact_form").submit();
        });
    });

(Something tells me that I may not be using the ng-model attributes correctly.)

Any ideas on where I am going wrong with this? Or ideas on how I can better go about implementing this design?

Thanks.


UPDATE BELOW:

Here is my entire updated controller code - with help from Sathish:

 // contacts controllers

'use strict';

function ContactListCtrl($scope, $http, Contacts) {   

  $scope.contacts = Contacts.index();  

  $scope.addContact = function() {
        var newContact = {
            first_name: $scope.newContactFirstName,
            last_name: $scope.newContactLastName
        };

        var nc = new Contacts({ contact: newContact });

        nc.$create(function() {
            $scope.contacts.push(nc);
            // now that the contact is saved, clear the form data
            $scope.newContactFirstName = "";
            $scope.newContactLastName = "";
            })
        }

};

ContactListCtrl.$inject = ['$scope', '$http', 'Contacts'];


function ContactDetailCtrl($scope, $routeParams, Contacts) {  
    $scope.contact = Contacts.get( {contact_id: $routeParams.contact_id} ); 
}

ContactDetailCtrl.$inject = ['$scope', '$routeParams', 'Contacts'];

I am now receiving the error: Unknown Provider for Contacts. Here is a screenshot of the error

Ok, I managed to fix that error by providing a ngResource to the main App file. Here's what it looks like:

// main app javascript file

'use strict';

angular.module('contactapp', ['ngResource']).
  config(['$routeProvider', function($routeProvider) {
  $routeProvider.
      when('/contacts', {template: 'assets/app/partials/contact-list.html',   controller: ContactListCtrl}).
      when('/contacts/new', {template: 'assets/app/partials/new-contact.html',   controller: ContactListCtrl}).
      when('/contacts/:contact_id', {template: 'assets/app/partials/contact-detail.html', controller: ContactDetailCtrl}).
      otherwise({redirectTo: '/contacts'});
}]);

I am receiving a new error: WARNING: Can't verify CSRF token authenticity

Alright, managed to fix that problem too by adding a callback to the API controller: Rails shows "WARNING: Can't verify CSRF token authenticity" from a RestKit POST

Now I am back to the original problem. When the create method is called, a new row is saved to the database, but the models data is not.

Awesome... finally got this thing working.

The problem was the $scope.addContact function. It was using the 'name' of the input instead of the ng-model binding called 'newFirstName' and 'newLastName' that resides in the template.

Here's what the updated function looks like:

$scope.addContact = function() {
        var newContact = {
            first_name: $scope.newFirstName,
            last_name: $scope.newLastName
        };

        var nc = new Contacts({ contact: newContact });

        nc.$create(function() {
            $scope.contacts.push(nc);
            // now that the contact is saved, clear the form data
            $scope.newFirstName = "";
            $scope.newLastName = "";
            })
        }

This can be better implemented using a Contacts service. Please define a Contacts service in app/assets/javascripts/services.js.erb as shown below:

var servicesModule = angular.module('<your app name>',
  [<list of modules needed by this app>]);

servicesModule.factory('Contacts', function($resource) {
  var ContactsService = $resource('/contacts/:contact_id', {}, {
    'create': { method: 'POST' },
    'index': { method: 'GET', isArray: true },
    'update': { method: 'PUT' },
    'destroy': { method: 'DELETE' }
  });
  return ContactsService;
});

Change the addContact method in the controller as shown below:

  function ContactListCtrl($scope, $http, Contacts) {
    ...
    ...
    ...
    $scope.addContact = function () {
      var newContact = {
        first_name: $scope.newContactFirstName,
        last_name: $scope.newContactLastName
      };

      var nc = new Contacts({ contact: newContact });
      nc.$create(function() {
        $scope.contacts.push(nc);
        // now that the contact is saved, clear the form data.
        $scope.newContactFirstName = "";
        $scope.newContactLastName = "";
      });
    };
    ...
    ...
    ...
  }
  ContactListCtrl.$inject = ['$scope', '$http', 'Contacts'];

In addition to this, you can simplify the $http.get(...) part also. You can use Contacts.index();

Note:

  • If you gave ng-app="MyAppName" then please replace <your app name> with MyAppName.
  • <list of modules needed by this app> needs to the replaced by a comma-separated list of strings representing any modules needed by your application.

Check the attr_accessible on your model. With new 3.2.3 rails all model attributes became protected from mass-assignment by default.