Mongodb + AngularJS: _id empty in update via resou

2020-07-27 03:51发布

问题:

I am using Mongodb (Rails 3 + Mongoid) and Angular JS.

In my db, I have a collection users which holds an array of objects addresses. I am trying to update the fields on an address in the array, but when I send the update request (using Angular's resourceProvider), all the _id that Angular sends to my server is "{}" (i.e. empty), so I end up with duplication instead of modification.

$scope.user.addresses holds non-blank ids and looks something like this:

[{_id:{$oid:"123431413243"}, text:"123 fake", cat:1},{_id:{$oid:"789789078907890}, text:"789 test", cat:7},...]

The PUT request body holds empty ids and looks something like this:

{"_id":{}, "user":{"addresses_attributes":[{"_id":{}, "text":"123 fake", "cat":"1"},{"_id":{}, "text":"789 test", "cat":"7"},...]}}

Angular JS code

myApp.factory('Users', ['$resource', function ($resource) {
    return $resource( '/users/:id.json', {id:0}, {update: {method:'PUT', _method:'PUT'}} );
}]);

myApp.controller('UsersCtrl', function ($scope, Users) {
    $scope.save = function () {
        $scope.user.$update({}, {user:$scope.user});
    };
});

Do you have any idea why this is and what I can do about it?

回答1:

It looks like there are two options here: override Angular JS’s transformation behavior or override Mongoid’s serializing behavior.

Option 1: Overriding Mongoid's serializing behavior

Add a file to override serializable_hash on Mongoid::Document.

# config/initializers/override_mongoid_serializable_hash.rb
module Mongoid
  module Document   

    def serializable_hash(options={})
      attrs = super
      attrs['id'] = attrs.delete('_id').to_s
      attrs
    end

  end
end

Don't simply try to override the as_json method because (for some reason) the new behavior that you define for that function will only apply to the object on which it is called (User), not on the included objects (Addresses).

Option 2: Overriding Angular JS's transforming behavior

Use the instructions in this answer: https://stackoverflow.com/a/12191613/507721

In short, in the call to myApp.config() in your Angular JS app, set your own function value for $httpProvider.default.transformRequest. The example from the answer linked above is as follows:

var myApp = angular.module('myApp');

myApp.config(function ($httpProvider) {
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return $.param(data);
    }
});

The body of the foregoing function is up to you. Transform it however is necessary.