rails中嵌套的强参数 - 期望的AssociationTypeMismatch MYMODEL,得到了ActionController :: Parameters()

时间:2014-01-31 21:19:40

标签: json ruby-on-rails-4 strong-parameters

我正在渲染一个模型,它是JSON中的子书籍,如下所示:

{"id":2,"complete":false,"private":false, "books" [{ "id":2,"name":"Some Book"},.....

然后我通过将相同的JSON传递回我的控制器来更新此模型,我收到以下错误:

ActiveRecord :: AssociationTypeMismatch(Book(#2245089560)预期,得到ActionController ::参数(#2153445460))

在我的控制器中,我使用以下内容进行更新:

@project.update_attributes!(project_params)

private

def project_params
    params.permit(:id, { books: [:id] } )
end

无论我在permit中将哪些属性列入白名单,我似乎无法保存子模型。

我错过了一些明显的东西吗?

更新 - 另一个例子:

控制器:

def create
    @model = Model.new(model_params)
end
def model_params
    params.fetch(:model, {}).permit(:child_model => [:name, :other])
end

请求:

post 'api.address/model', :model => { :child_model => { :name => "some name" } }

型号:

accepts_nested_attributes_for :child_model

错误:

期望的ChildModel,得到了ActionController :: Parameters

尝试此方法无济于事:http://www.rubyexperiments.com/using-strong-parameters-with-nested-forms/

6 个答案:

答案 0 :(得分:12)

您是否在项目模型上使用accepts_nested_attributes_for :books?如果是,则密钥应为"books"而不是"books_attributes"

def project_params
  params.permit(:id, :complete, :false, :private, books_attributes: [:id, :name])
end

答案 1 :(得分:8)

我正在使用Angular.js& Rails& Rails序列化器,这对我有用:

<强>模型

  • has_many:features
  • accepted_nested_attributes_for:features

ModelSerializer

  • has_many:features,root :: features_attributes

<强>控制器

  • params.permit features_attributes:[:id,:enabled]

<强> AngularJS

  • ng-repeat =“feature.features_attributes中的功能跟踪feature.id

答案 2 :(得分:7)

我使用ember.js解决这个问题的方法是设置books_attributes mannualy。

在控制器中:

def project_params      
  params[:project][:books_attributes] = params[:project][:books_or_whatever_name_relationships_have] if params[:project][:books_or_whatever_name_relationships_have]
  params.require(:project).permit(:attr1, :attr2,...., books_attributes: [:book_attr1, :book_attr2, ....])

end

因此rails会按预期的方式检查和过滤嵌套属性

答案 3 :(得分:0)

这对我有用。我的父模型是Artist,子模型是Url

class ArtistsController < ApplicationController

  def update
    artist = Artist.find(params[:id].to_i)
    artist.update_attributes(artist_params)
    render json: artist
  end

private

  def artist_params
    remap_urls(params.permit(:name, :description, urls: [:id, :url, :title, :_destroy]))
  end

  def remap_urls(hash)
    urls = hash[:urls]
    return hash unless urls
    hash.reject{|k,v| k == 'urls' }.merge(:urls_attributes => urls)
  end
end

class Artist < ActiveRecord::Base
  has_many :urls, dependent: :destroy
  accepts_nested_attributes_for :urls, allow_destroy: true
end

class Url < ActiveRecord::Base
  belongs_to :artist
end

...和coffeescript(处理删除):

  @ArtistCtrl = ($scope, $routeParams, $location, API) ->

    $scope.destroyUrls = []

    $scope.update = (artist) ->
      artist.urls.push({id: id, _destroy: true}) for id in $scope.destroyUrls
      artist.$update(redirectToShow, artistError)

    $scope.deleteURL = (artist,url) ->
      artist.urls.splice(artist.urls.indexOf(url),1)
      $scope.destroyUrls.push(url.id)

答案 4 :(得分:0)

所有答案中都缺少某些内容,这是undefined形式的输入。

如果执行此操作,表单将起作用:

fields_for

但是,表单以f.fields_for @model.submodel do .. 的形式发送,但这就是导致其他人在其答案中提到的错误的原因。如果尝试执行model[submodel],Rails会引发错误,提示您期望使用model.update(model_params)类型。

要解决此问题,请确保遵循Submodel格式:

:name, value

然后在控制器中,确保将f.fields_for :submodel, @model.submodel do ... 放在参数上:

_attributes

现在,保存,更新等将正常工作。

答案 5 :(得分:-3)

浪费了几天时间试图找出如何在Angular中使用accepts_nested_attributes,问题总是一样的:Rails白名单不会允许变量进入params哈希。我尝试了每个人在SO和其他博客上说的每个不同的白名单语法,尝试使用:反向,尝试使用habtm和mas_many_through,尝试手动滚动我自己的解决方案,但如果白名单不允许参与通过,那就不会工作,尝试做什么http://guides.rubyonrails.org说“在强参数范围之外”,尝试将所有这些列入白名单,这不是一个真正的选择,但无论如何都会导致其他问题。不确定为什么rails 4强参数白名单不会允许任意数据通过,这是一个巨大的问题,特别是如果accepts_nested_attributes也不起作用....我想我们只是在一个单独的页面/表单/控制器上创建/删除所有关联并且看起来像个白痴,让我的最终用户使用多个表单/页面做一些应该可以在1页上轻松完成的表格。我知道,通常我希望Angular能够搞砸我,但是这次Angular工作得非常好,实际上Rails 4在一个问题上让我两次搞砸了,这应该是非常简单的。