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

Posted

技术标签:

【中文标题】Backbone 和 Rails 关联:避免 JSON HashWithIndifferentAccess 错误【英文标题】:Backbone and Rails associations: Avoiding JSON HashWithIndifferentAccess errors 【发布时间】:2012-02-01 16:39:46 【问题描述】:

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

在 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"=>"第二次测试 post", "updated_at"=>"2012-01-03T10:51:09Z", "cmets"=>[], "id"=>"2" Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE “帖子”。“id”=? LIMIT 1 [["id", "2"]] 警告:不能批量分配 受保护的属性: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:inupdate'

一些事情:

这是触发的(例如):

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

另外,是的,模型中存在“accepts_nested_attributes_for”。

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

RAILS 'POST' 模型

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'

【问题讨论】:

【参考方案1】:

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

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

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

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

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

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

# 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

希望这会有所帮助。

【讨论】:

【参考方案2】:

对于那些正在谷歌搜索的人......

虽然当前接受的答案确实有效,但以下是我解决问题的方法(非常相似,但略有不同):

我使用的是nested form,模型嵌套了 4 层深。在呈现表单的控制器中,我需要构建表单。

def new
  @survey = Survey.new
  3.times do
    question = @survey.questions.build
    4.times  question.answers.build 
  end
end

这允许参数包含params[:survey][:questions_attributes]。 Rails 为我重命名了参数,因为我提前通知了它。

希望这会有所帮助!

【讨论】:

以上是关于Backbone 和 Rails 关联:避免 JSON HashWithIndifferentAccess 错误的主要内容,如果未能解决你的问题,请参考以下文章

Backbone.js 前端和 RESTful Rails 后端?

markdown Rails和Backbone.js设置

Backbone.js 和嵌入式一对多关联

Rails、Backbone、PhoneGap、CORS(Access-Control-Allow-Origin 错误不允许)

Backbone.js 中的模型

Backbone.js + Handlebars 各