I'm writing a practice Backbone app, with Rails backend API, and I'm confused about the behavior of save on Backbone models.
Let's say a Team has many Players, and I want to save a team with numerous players in a single POST.
So in Rails I have:
class Team < ActiveRecord::Base
has_many :players
accepts_nested_attributes_for :players
end
class Player < ActiveRecod::Base
belongs_to :team
end
and for backbone client, I have a Player model and a Players collection defined (not shown)
and then the containing Team model (NOTE: no Teams collection)
Demo.Models.Team = Backbone.Model.extend({
urlRoot: '/teams',
defaults: {
'team_size': 12
},
initialize: function() {
this.players = new Demo.Collections.Players());
},
toJSON: function() {
var json = _.clone(this.attributes);
json.players_attributes = this.players.map(function(player) {
return player.toJSON();
});
return json;
}
}
When I examine my stringified JSON in the browser, everything looks good:
{"team_size":12, "players_attributes":[{"name":"Fred"},{"name":"Jim" },{"name":"Mark"}]}
Checking the server logs, the lone top level attribute ('team size') is repeated, once at the top level, and then repeated under a root key.
Started POST "/teams" for 127.0.0.1 at 2012-06-07 13:39:40 -0400
Processing by TeamsController#create as JSON
Parameters: {
"team_size"=>12, "players_attributes":[{"name":"Fred"},{"name":"Jim" },{"name":"Mark"}]},
"team"=>{"team_size"=>12}
}
I have a few questions:
What's the best way to ensure the player_attributes are nested inside the root key? I (So that I can do a nested save inside TeamController, in the standard rails manner: (i.e. Team.create(params[:team]) ) I can accomplish this with some javascript hackery inside toJSON, but I'm guessing there's an easier, cleaner way.
Is this standard, desirable behaviour? To send duplicates of attributes like this? I guess there's no harm, but it doesn't smell right.
Am I not defining the url / urlRoot correctly or some such?
thanks
1- You have to override the toJSON method in order to include the model name as the root of the JSON element sent to the server.
toJSON: function() {
return { team: _.clone( this.attributes ) }
},
Since you are already messing and overriding this method I don't see any reasons not to go this way.
2- This is a very strange behavior you're describing. Try:
class Team < ActiveRecord::Base
self.include_root_in_json = false
end
It will probably eliminate Rails duplicate params parsing. Another advantage you get from this is that Rails won't include the team as a root element of its generated JSON to the client.
3- Your definition of urlRoot is just fine.