Búsqueda de sitios web

javascript - AngularJS - $http POST con Rails 3.2.3


Estoy construyendo una aplicación simple de gestión de contactos con CRUD usando AngularJS 1.0.0rc8.

Obtener una lista de contactos que existen actualmente no es un problema, pero al intentar guardar un nuevo Contacto en el servidor, se crea una nueva fila, completa con el id correcto, y los valores de created_at y updated_at, pero el resto de los datos del modelo se ignoran.

Aquí hay una captura de pantalla para mostrar lo que quiero decir:

Como puedes ver, a los números 4 y 5 se les asignaron los Id, pero first_name, last_name y phone_num no se guardaron en la base de datos.

Estoy usando una función $scope.addContact dentro del Controlador que maneja el objeto.

Aquí está todo el código del Controlador de la Lista de Contactos:

'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 = '';
  };

};

Después de hacer clic en 'Guardar' en el parcial new-contact.html, el Objeto se registra en la Consola, si inspecciono su contenido, entonces, efectivamente, se recopilan los valores: observe que Jimi Hendrix está ahí:

Aquí está el formulario tal como aparece en la plantilla new-contact.html:

<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>

La función addContact() se ejecuta después de que el formulario se envía con JQuery:

$(document).ready(function(){       

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

(Algo me dice que puede que no esté usando los atributos ng-model correctamente.)

¿Alguna idea de dónde estoy equivocándome con esto? ¿O alguna idea de cómo puedo implementar mejor este diseño?

Gracias.

ACTUALIZACIÓN A CONTINUACIÓN:

Aquí está todo mi código de controlador actualizado - con la ayuda de 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'];

Ahora estoy recibiendo el error: Proveedor desconocido para Contactos. Aquí hay una captura de pantalla del error

Ok, logré arreglar ese error proporcionando un ngResource al archivo principal de la App. Así es como se ve:

// 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'});
}]);

Estoy recibiendo un nuevo error: ADVERTENCIA: No se puede verificar la autenticidad del token CSRF

Muy bien, también logré solucionar ese problema agregando un callback al controlador de la API: Rails muestra "ADVERTENCIA: No se puede verificar la autenticidad del token CSRF" desde un POST de RestKit

Ahora he vuelto al problema original. Cuando se llama al método create, se guarda una nueva fila en la base de datos, pero los datos del modelo no.

Increíble... finalmente hice que esto funcionara.

El problema era la función $scope.addContact. Estaba usando el 'name' del input en lugar del enlace ng-model llamado 'newFirstName' y 'newLastName' que se encuentra en la plantilla.

Aquí está cómo se ve la función actualizada:

$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 = "";
            })
        }

Respuesta #1

Esto se puede implementar mejor utilizando un servicio de Contactos. Por favor, defina un servicio de Contactos en app/assets/javascripts/services.js.erb como se muestra a continuación:

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;
});

Cambia el método addContact en el controlador como se muestra a continuación:

  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'];

Además de esto, también puedes simplificar la parte $http.get(...). Puedes usar Contacts.index();

Nota:

  • Si pusiste ng-app="MyAppName" entonces por favor reemplaza <tu nombre de aplicación> con MyAppName.
  • <list of módulos necesarios para esta aplicación> necesita ser reemplazado por una lista separada por comas de cadenas que representen los módulos necesarios para su aplicación.

Respuesta #2

Revisa el attr_accessible en tu modelo. Con Rails 3.2.3 nuevo, todos los atributos del modelo se volvieron protegidos contra la asignación masiva por defecto.