使用params哈希保存嵌套表单时出现问题

时间:2013-11-24 00:01:38

标签: ruby-on-rails forms activerecord nested-forms

我正在尝试创建一个可以编辑然后保存的嵌套表单。每当我去保存表单时,我都会收到错误:

  

对于ID =

的Collection,找不到ID为11的ClassInstance

11是表单中第一个ClassInstance的ClassInstance id,看起来Collection ID被设置为NULL。

我尝试在控制器form_for中手动设置隐藏ID,并在_class_instance_fields.html.erb中为:collection_id设置隐藏字段。

ActiveRecord尝试做什么,为什么会混淆?我是否会使用嵌套表格做一些你不应该做的事情?

我已经将我的一些代码包含在去除绒毛中,因此无需查看。

collections_controller.rb

 def update
    @collection = Collection.new(params[:collection])

    if @collection.save
      flash[:notice] = "IT WORKED"
    else
      flash[:notice] = "No Cigar...."
    end
    redirect_to collection_path
  end

  def read
      @collection = Collection.find_by_user_id(current_user.id)
      @classes = Classification.all 
  end

read.html.erb

<%= form_for @collection, url: {:action => "update", collection_id: @collection.id} do  |f| %>
        <%= f.hidden_field :id #I had hoped this would fix it%>
        <table class="instance_table">
                <%= f.fields_for :class_instances do |builder| %>
                    <%= render 'shared/class_instance_fields', :f => builder, :status => '0' %>
                <% end %>
                <tr><td>
                    <%= link_to_add_fields "Add an Instance", f, :class_instances  %>
                </td></tr>
        </table>
        <%= f.submit "Save"%>
    <% end %>

_class_instance_fields.html.erb

<tr class="record_row">
    <td>
        <%=  f.label( :name) %></p>
    </td>
        <%= f.hidden_field :status, :value => status  %>
        <%= f.hidden_field :collection_id %>
    <td>
        <% if status == '1'  %>
            <%= f.text_field :name %>
        <% else %>
            <%= link_to f.object.name, instance_edit_path(f.object.id) %>
        <% end %>
    </td>
    <td>
        <% if status == '1' %>
            <%=  f.select :classification, options_for_select(@classes.collect{|c| [c.name, c.id]},selected:  f.object.class_id)%>
        <% else %>
            <%= f.label :classification,  displayClassInstanceName(@classes.select{|a|  a[:id] == f.object.class_id }[0])  %>
        <% end %>
    </td>
    <td>
        <% user = nil%>
        <% id = nil %>
        <% if status == '1' %>
            <%collection = current_user.id %>
        <% else %>
            <%collection = f.object.collection_id %>
        <% end %>
        <%= f.label :username, displayUserName( user ) %>

    </td>
    <td>
        <%= removeRecordLink(f) %>
    </td>

</tr>

其他信息

在保存之前,我一直在使用Rails.logger.debug检查参数。使用`update

中的后续代码
Rails.logger.debug "TG: " << params.to_yaml

我得到以下输出

TG: --- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
utf8: ✓
_method: put
authenticity_token: efvqGsLKJfdCsadfjsad9fsD97dfgYaOUjsg+uvAQi2+k4=
collection: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  name: mikee's Collection
  class_instances_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
    '0': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
      status: '0'
      collection_id: '8'
      _destroy: '0'
      instance_attributes_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
        '0': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
          id: '1'
          _destroy: '0'
      id: '11'
commit: Save
controller: collections
action: update
id: '8'

也许这可以帮助理解事物,因为我对params不太熟悉,而且我不确定我应该在那里看到嵌套表格。

3 个答案:

答案 0 :(得分:1)

我想对您的帖子发表评论但尚未获得50个声望......所以我只想发布此处。希望你会发现它有用。

您是否在表单前尝试<%= @collection.inspect %>以查看Rails正在将哪些数据放入表单中?您不必在任何地方指定idcollection_id,因为form_for会照顾您。

我会在表单中注释掉其余字段,然后在render text: params.inspect and return操作中执行update,以确切了解通过PATCH向其发送的数据(假设您正在运行) Rails 4)。

如果id(或collection_id取决于您的路线)显示正确,那么您可以开始取消注释表单的某些部分...冲洗并重复,直到找到有问题的代码。

编辑:我同意Philip7899。这似乎是一个很强的参数问题。

答案 1 :(得分:1)

与其他人相反,我不相信这是一个强大的参数问题。当您说params.require(:collection)之类的内容时,强参数才会启动。

我很难理解你在这里要做什么。您的方法称为更新,它表示它更新现有记录,而是创建一个新记录(Collection.new)。我假设您正在尝试更新现有记录。

这里有一些问题。首先是控制器。替换这个:

@collection = Collection.new(params[:collection])

用这个:

@collection = Collection.find(params[:id])
@collection.assign_attributes(params[:collection])

然后是视图......

当表单更新Rails中的资源时,标准过程是在表单操作URL中包含对象ID。当您使用form_for @collection时会自动发生这种情况。由于您使用url: {:action => "update", collection_id: @collection.id}覆盖了表单的URL,因此它无法正确生成路径。将您的form_for行更改为:

<%= form_for @collection do |f| %>

并删除f.hidden_field :id

要使其正常工作,您必须在routes.rb中设置相应的路线。我假设你在那里有一行,如resources :collections

我无法告诉您要对class_instances做什么,但是如果您希望在保存集合时创建其他对象,则可能需要在Collection模型上设置accepts_nested_attributes_for 。在这里阅读:

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

一旦这样做,您可能希望将params[:collection]替换为collection_params,然后您应该向控制器添加方法

protected
def collection_params
  params.require(:collection).permit(:param_1, :param_2, :param_3)
end

其中:param_1,:param_2,:param_3是您希望允许用户更新的参数。

请参阅https://github.com/rails/strong_parametersRails 4 - Strong Parameters - Nested Objects

答案 2 :(得分:0)

如果您使用的是rails 4,请将class:id添加到class_instances的强参数中。如果您使用的是rails 3,请对模型进行更改,以便用户可以对其进行设置。