【问题标题】:Problems saving my nested form using the params hash使用 params 哈希保存我的嵌套表单时出现问题
【发布时间】:2013-11-24 00:01:37
【问题描述】:

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

无法为 ID=11 的 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'

也许这可以帮助理解事情,因为我对参数没有太多经验,而且我不确定我应该在嵌套表单中看到什么。

【问题讨论】:

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


    【解决方案1】:

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

    我很难理解您在这里要做什么。您的方法称为 update,这表明它更新了现有记录,而是创建了一条新记录 (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 =&gt; "update", collection_id: @collection.id} 覆盖表单的url,因此它没有正确生成路径。将您的 form_for 行更改为:

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

    并删除f.hidden_field :id

    要使其正常工作,您必须在routes.rb 中设置适当的路由。我假设您在其中有一条线,例如resources :collections

    我不知道您想用 class_instances 做什么,但如果您希望在保存集合时创建其他对象,您可能需要在集合模型上设置 accepts_nested_attributes_for。在这里阅读:

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

    一旦它工作了,你可能想用collection_params替换params[:collection],然后你应该向你的控制器添加一个方法

    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

    【讨论】:

    • 感谢您帮助我了解我的表格搞砸了什么。这实际上困扰了我一段时间!我认为我使用 new 来更新模型真的很奇怪,当我意识到我在制作控制器时正在查看示例中的错误操作时,我踢了自己。
    • 是的,我做到了,尝试使用 new 是愚蠢的,使用 assign_attributes 修复了我!发现我错过了如此微小的细节令人沮丧和宽慰:P 再次感谢!下一个问题:P
    【解决方案2】:

    我想对你的帖子发表评论,但还没有 50 声望……所以我就在这里发帖。希望对您有所帮助。

    您是否在表单之前尝试过&lt;%= @collection.inspect %&gt;,以查看 Rails 将哪些数据放入表单中?您不必在任何地方指定idcollection_id,因为form_for 会为您处理。

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

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

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

    【讨论】:

    • 不幸的是,我已经在做类似的事情了。我一直在使用Rails.logger.debug 来检查表单传递给控制器​​的内容。我觉得我已经用我提供的领域做了很多冲洗和起泡。我将用我得到的输出结果更新我的问题,也许这可以阐明一些问题,因为我不太确定它应该是什么样子
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-06
      • 2013-04-21
      • 2016-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-28
      相关资源
      最近更新 更多