Rails 4不通过JSON更新嵌套属性

我已经搜索了相关的问题,但仍然有问题从我的AngularJS前端返回的rails 4到JSON中更新嵌套属性。

问题:下面的代码概述了从我的Rails4应用程序中从AngularJS传递到Candidate模型的JSON。 Candidate模型有很多Works,我正在尝试通过Candidate模型更新Works模型。 由于某种原因,Works模型无法更新,我希望有人可以指出我缺少的东西。 谢谢你的帮助。


这是候选人AngularJS前端的json:

{"id"=>"13", "nickname"=>"New Candidate", "works_attributes"=>[ {"title"=>"Financial Analyst", "description"=>"I did things"}, {"title"=>"Accountant", "description"=>"I did more things"}]} 

然后,Rails通过添加候选标头将此JSON转换为以下内容,但不包括候选标头下的嵌套属性,并且无法通过候选模型更新works_attributes

 {"id"=>"13", "nickname"=>"New Candidate", "works_attributes"=>[ {"title"=>"Financial Analyst", "description"=>"I did things"}, {"title"=>"Accountant", "description"=>"I did more things"}], "candidate"=>{"id"=>"13", "nickname"=>"New Candidate"}} 

candidate_controller.rb包含一个简单的更新:

 class CandidatesController < ApplicationController before_filter :authenticate_user! respond_to :json def update respond_with Candidate.update(params[:id], candidate_params) end private def candidate_params params.require(:candidate).permit(:nickname, works_attributes: [:id, :title, :description]) end end 

candidate.rb模型包含以下代码,用于定义与工作模型的has_many关系:

 class Candidate  :destroy ## Nested model attributes accepts_nested_attributes_for :works, allow_destroy: true ## Validations validates_presence_of :nickname validates_uniqueness_of :user_id end 

最后,works.rb模型定义了has_many关系的另一面:

 class Work < ActiveRecord::Base belongs_to :candidate end 

我感谢您提供的任何帮助,因为我确信我错过了一些相当简单的东西。

谢谢!

我也一直在使用Rails和AngularJS之间的JSON API。 我使用与RTPnomad相同的解决方案,但找到了一种不必硬编码include属性的方法:

 class CandidatesController < ApplicationController respond_to :json nested_attributes_names = Candidate.nested_attributes_options.keys.map do |key| key.to_s.concat('_attributes').to_sym end wrap_parameters include: Candidate.attribute_names + nested_attributes_names, format: :json # ... end 

请参阅Rails中的此问题 ,以了解是否/何时解决此问题。

更新10/17
等待公关合并: rail / rails#19254 。

我想出了一种基于rails文档来解决我的问题的方法: http : //edgeapi.rubyonrails.org/classes/ActionController/ParamsWrapper.html

基本上,Rails ParamsWrapper默认情况下启用从前端包装JSON,并在Rails中使用根元素,因为AngularJS不会在根包装元素中返回数据。 以上文档包含以下内容:

“在没有:include或:exclude选项集的ActiveRecord模型中,它只会包装类方法attribute_names返回的参数。”

这意味着我必须使用以下语句显式包含嵌套属性,以确保Rails包含所有元素:

 class CandidatesController < ApplicationController before_filter :authenticate_user! respond_to :json wrap_parameters include: [:id, :nickname, :works_attributes] ... 

如果有更好的方法在AngularJS和Rails之间传递JSON数据,请添加此问题的另一个答案

您还可以将patch参数包装设置为始终包含nested_attributes,方法是将其放入例如wrap_parameters.rb初始化程序中:

  module ActionController module ParamsWrapper Options.class_eval do def include return super if @include_set m = model synchronize do return super if @include_set @include_set = true unless super || exclude if m.respond_to?(:attribute_names) && m.attribute_names.any? self.include = m.attribute_names + nested_attributes_names_array_of(m) end end end end private # added method. by default code was equivalent to this equaling to [] def nested_attributes_names_array_of model model.nested_attributes_options.keys.map { |nested_attribute_name| nested_attribute_name.to_s + '_attributes' } end end end end