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

RTP*_*mad 12 json ruby-on-rails nested-attributes ruby-on-rails-3 ruby-on-rails-4

我已经搜索了相关的问题,但仍然有问题从我的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"}]}
Run Code Online (Sandbox Code Playgroud)

然后,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"}}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

class Candidate < ActiveRecord::Base

  ## Model Relationships
  belongs_to :users
  has_many :works, :dependent => :destroy  

  ## Nested model attributes
  accepts_nested_attributes_for :works, allow_destroy: true

  ## Validations
  validates_presence_of :nickname
  validates_uniqueness_of :user_id

end
Run Code Online (Sandbox Code Playgroud)

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

class Work < ActiveRecord::Base
  belongs_to :candidate
end
Run Code Online (Sandbox Code Playgroud)

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

谢谢!

kma*_*ana 7

我也一直在使用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
Run Code Online (Sandbox Code Playgroud)

请参阅Rails中的这个问题,看看他们是否/何时解决了这个问题.

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


RTP*_*mad 6

我想出了一种基于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]
    ...
Run Code Online (Sandbox Code Playgroud)

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

  • 我正在使用活动模型序列化器从rails生成JSON输出.paramswrapper根据上面的文档简化了传入的JSON:"将参数哈希包装成嵌套哈希.这将允许客户端提交POST请求而无需指定任何根元素. (3认同)