为什么Backbone模型会在保存时向服务器发送重复属性?

时间:2012-06-07 17:49:51

标签: javascript ruby-on-rails ruby backbone.js nested-attributes

我正在编写一个使用Rails后端API的练习Backbone应用程序,我对在Backbone模型上保存的行为感到困惑。

假设一个团队有很多玩家,我想在一个POST中保存一个拥有众多玩家的团队。

所以在Rails中我有:

class Team < ActiveRecord::Base
  has_many :players
  accepts_nested_attributes_for :players
end

class Player < ActiveRecod::Base
  belongs_to :team
end

对于骨干客户端,我有一个播放器模型和播放器集合定义(未显示)

然后包含Team模型(注意:没有团队集合)

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

当我在浏览器中检查我的字符串化JSON时,一切看起来都不错:

{"team_size":12, "players_attributes":[{"name":"Fred"},{"name":"Jim" },{"name":"Mark"}]}

检查服务器日志,重复一次顶级属性('团队规模'),一次在顶级,然后在根密钥下重复。

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

我有几个问题:

  1. 确保player_attributes嵌套在根密钥中的最佳方法是什么?我(所以我可以在标准的rails方式中在TeamController中进行嵌套保存:(即Team.create(params [:team]))我可以用toJSON中的一些javascript hackery来完成这个,但我猜是有一个更简单,更清洁的方式。

  2. 这是标准的,理想的行为吗?要发送像这样的重复属性?我想这没什么坏处,但它闻起来不对。

  3. 我没有正确定义url / urlRoot还是其他一些?

  4. 感谢

3 个答案:

答案 0 :(得分:3)

1-您必须覆盖toJSON方法,以便将模型名称包含为发送到服务器的JSON元素的根目录。

 toJSON: function() {
    return { team: _.clone( this.attributes ) }
  },

由于你已经搞乱并覆盖了这种方法,我认为没有任何理由不这样做。

2-这是你描述的一种非常奇怪的行为。尝试:

class Team < ActiveRecord::Base
  self.include_root_in_json = false
end

它可能会消除Rails重复的params解析。您从中获得的另一个好处是Rails不会将团队作为其生成的JSON的根元素包含在客户端中。

3-你对urlRoot的定义很好。

答案 1 :(得分:0)

我在找同样的问题时到了这里。所以,即使这是一个老问题,我认为值得给出答案。

我实际上找到了一个解释这些重复属性的Rails设置:wrap_parameters

http://apidock.com/rails/v3.2.13/ActionController/ParamsWrapper/ClassMethods/wrap_parameters

只需将其设置为空数组,rails就不会尝试包装来自JSON请求的参数。

答案 2 :(得分:0)

虽然你可以使用别人提到的toJSON黑客,但实际上并不是一个好主意。例如,它在syncsave{patch: true}之间产生不一致的结果(这种不一致是因为如果不修补,则sync方法调用JSON,但如果不修补则不调用toJSON你有补丁设置为真)

相反,更好的解决方案是使用Backbone的修补版本来重载同步方法本身。 backbone-rails gem会自动执行此操作,或者您可以将backbone_rails_sync.js拉入您自己的应用程序。可以在此处找到有关此问题的更完整答案:Backbone.js and Rails - How to handle params from Backbone models?