Backbone 和 Rails 关联:避免 JSON HashWithIndifferentAccess 错误

我正在尝试让我的骨干关联在 rails 应用程序中工作,但在尝试更新现有模型时遇到了困难.具体来说,Rails 会抛出以下错误:

I'm trying to get my backbone associations working inside a rails app , and I'm having difficulty when trying to update existing models. Specifically, Rails throws the following error:

在 2012-01-04 02:36:14 +1000 开始为 127.0.0.1 放置/posts/2"
PostsController#update 处理为 JSON 参数:{"post"=>{"content"=>"Seconderona","created_at"=>"2012-01-03T10:51:09Z", "id"=>2, "title"=>"第二次测试发布",updated_at"=>2012-01-03T10:51:09Z",评论"=>[{}]},"id"=>"2"} Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE帖子".id"=?LIMIT 1 [["id", "2"]] 警告:不能批量分配受保护的属性:id Completed 500 Internal Server Error in 15ms

Started PUT "/posts/2" for 127.0.0.1 at 2012-01-04 02:36:14 +1000
Processing by PostsController#update as JSON Parameters: {"post"=>{"content"=>"Seconderona", "created_at"=>"2012-01-03T10:51:09Z", "id"=>2, "title"=>"Second test post", "updated_at"=>"2012-01-03T10:51:09Z", "comments"=>[{}]}, "id"=>"2"} Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1 [["id", "2"]] WARNING: Can't mass-assign protected attributes: id Completed 500 Internal Server Error in 15ms

ActiveRecord::AssociationTypeMismatch (评论(#70104367824560)预期,得到ActiveSupport::HashWithIndifferentAccess(#70104367278120)):
app/controllers/posts_controller.rb:62:in block in update'
app/controllers/posts_controller.rb:61:in
update'

ActiveRecord::AssociationTypeMismatch (Comment(#70104367824560) expected, got ActiveSupport::HashWithIndifferentAccess(#70104367278120)):
app/controllers/posts_controller.rb:62:in block in update'
app/controllers/posts_controller.rb:61:in
update'

一些事情:

这是触发的(例如):

c = window.router.comments.models[0]
c.save({content: 'Changed content'})

另外,是的,模型中存在accepts_nested_attributes_for".

Also, yes, 'accepts_nested_attributes_for' is present in the model.

下面的(有问题的)代码几乎一字不差地取自 thougtbot 的backbone on rails"电子书,我还尝试遵循骨干关系 gem 的文档.两者都会引发此错误.任何想法表示赞赏,下面的代码

The (offending) code below is taken pretty much verbatim from thougtbot's "backbone on rails" ebook, and I've also tried following the documentation for the backbone-relational gem. Both raise this error. Any ideas appreciated, code below

class Post < ActiveRecord::Base
  has_many :comments

  accepts_nested_attributes_for :comments

  def as_json(options = nil)
    super((options || {}).merge(include: { comments: { only: [content] } } ))
  end
end

铁路评论"模型

class Comment < ActiveRecord::Base
  belongs_to :post

  accepts_nested_attributes_for :post

  def as_json(options = nil)
    super((options || {}).merge(include: { post: { only: [:title, :content]}}))
  end
end

骨干后控制器

class Backbonerelationaldemo.Models.Post extends Backbone.Model
  paramRoot: 'post'

  initialize: () ->
    comments = new Backbonerelationaldemo.Collections.CommentsCollection
    comments.reset(@get('comments'))
    @setComments(comments)

  setComments: (comments) ->
    @comments = comments


class Backbonerelationaldemo.Collections.PostsCollection extends Backbone.Collection
  model: Backbonerelationaldemo.Models.Post
  url: '/posts'

主干评论控制器

class Backbonerelationaldemo.Models.Comment extends Backbone.Model
  paramRoot: 'comment'

  initialize: () ->
    if (@has('post')) 
      @setPost(new Backbonerelationaldemo.Models.Post(@get('post')))

  setPost: (post) ->
    @post = post

class Backbonerelationaldemo.Collections.CommentsCollection extends Backbone.Collection
  model: Backbonerelationaldemo.Models.Comment
  url: '/comments'

推荐答案

我最近处理了同样的问题.这实际上不是 HashWithIndifferentAccess 错误:它与 accepts_nested_attributes_for 期望参数的方式有关.

I dealt with the same issue recently. It's actually not a HashWithIndifferentAccess error: it has to do with how accepts_nested_attributes_for expects params.

当您声明 accepts_nested_attributes_for :comments 时,Rails 会在传入参数上查找参数调用 comments_attributes.

When you declare accepts_nested_attributes_for :comments, Rails looks for a parameter call comments_attributes on the incoming params.

问题是来自 Backbone 的 JSON 表示具有 "comments" 属性而不是 "comments_attributes" 属性.

The problem is that your JSON representation coming from Backbone has a "comments" property instead of a "comments_attributes" property.

您可以通过向 Post 模型添加 toJSON 函数来在 Backbone 端修复它:

You could fix it on the Backbone side by adding a toJSON function to your Post model:

# in your Post model
toJSON: ->
  attrs = _.clone(@attributes)
  attrs.comments_attributes = _.clone(@attributes.comments)
  delete attrs.comments
  attrs

或者您可以在 Rails 控制器中处理它:

Or you could handle it in your Rails controller:

# in your Posts controller
def update
  params[:comments_attributes] = params.delete(:comments) if params.has_key? :comments
  # call to update_attributes and whatever else you need to do
 end

希望这会有所帮助.

相关文章