Rails 5 HABTM不允许的参数

时间:2018-08-14 22:27:42

标签: ruby-on-rails activerecord nested has-and-belongs-to-many

一天都无处可去之后,我就把毛巾扔了(答案可能很烦人,但这就是代码)。

好的,我有2个模型,用户(带有Devise)和章节。

型号:

class User < ApplicationRecord
  has_many :projects
  has_and_belongs_to_many :chapters
end

class Chapter < ApplicationRecord
  belongs_to :country
  has_and_belongs_to_many :users
  accepts_nested_attributes_for :users
end

_form.html.erb

[...]
<% @chapter.users.each_with_index do |chap_user, i| %>
  <div class="row">
    <div class="col-md-4 col-md-offset-4  col-xs-8 col-xs-offset-2">
      <small>User <%= i + 1 %></small>
    </div>
  </div>

  <div class="row">
    <div class="col-md-2 col-md-offset-4  col-xs-8 col-xs-offset-2">

      <div class="field form-group">
        <%= form.label 'First Name' %>
        <%= form.text_field :first_name, value: chap_user.first_name,class:"form-control"%>
      </div>
    </div>
    <div class="col-md-2 col-md-offset-0 col-xs-8 col-xs-offset-2">
      <div class="field form-group">
        <%= form.label 'Last Name' %>
        <%= form.text_field :last_name, value: chap_user.last_name, class:"form-control"%>
      </div>

    </div>
  </div>
  <div class="row">
    <div class="col-md-4 col-md-offset-4 col-xs-8 col-xs-offset-2">
      <div class="field form-group">
        <%= form.label :email %>
        <%= form.text_field :email, value: chap_user.email, class:"form-control"%>
      </div>

    </div>
  </div>
<% end %>
[...]

ChaptersController(参数)

私人     #使用回调在操作之间共享通用的设置或约束。     def set_chapter       @chapter = Chapter.find(params [:id])     结束

# Never trust parameters from the scary internet, only allow the white list through.
def chapter_params
  params.fetch(:chapter, {})
  params.require(:chapter).permit(:city, :country_id, user_attributes: [:first_name,:last_name,:email])
end
# or...
params.require(:chapter).permit(:city, :country_id, user_ids: [])
# or...
params.require(:chapter).permit(:city, :country_id, user_attributes: [:id, :first_name])
# or...
params.require(:chapter).permit(:city, :country_id, users_attributes: [:id, :first_name])

binding.pry在控制器中

  # PATCH/PUT /chapters/1
  # PATCH/PUT /chapters/1.json
  def update
    binding.pry
    respond_to do |format|
      if @chapter.update(chapter_params)
        format.html { redirect_to @chapter, notice: 'Chapter was successfully updated.' }
        format.json { render :show, status: :ok, location: @chapter }
      else
        format.html { render :edit }
        format.json { render json: @chapter.errors, status: :unprocessable_entity }
      end
    end
  end

binding.pry响应

我知道这有点丑陋,但基本上已经提交了参数,但是不允许用户[:first_name,:last_name,:email]

[1] pry(#)>章节参数 不允许的参数::first_name,:last_name,:email =>“ London”,“ country_id” =>“ 1”}允许:true> [2] pry(#)> params =>“✓”,“ _method” =>“ patch”,“ authenticity_token” =>“ 9IdAqcAsVG5vvakSf7jHRk + WplN / GyVZUxmAdefUbTX / uI6IajmZPr1YSol21Zhzdl7P / N>” “ London”,“ country_id” =>“ 1”,“ first_name” =>“ Tim2”,“ last_name” =>“ Heard”,“ email” =>“ jmcgregorx@spartaglobal.com”}允许:false>,“允许提交“ =>”更新“,”控制器“ =>”章节“,”操作“ =>”更新“,” id“ =>” 1“}:false>

简而言之,我想通过表单将某些用户连接到某些章节,但是我不知道如何通过章节update / create方法来获取嵌套的参数。我的头是红色的,泥泞的烂摊子。请帮忙。

1 个答案:

答案 0 :(得分:0)

由于您要修改的字段是针对子模型的,因此您必须告诉表单,因为它假定您默认情况下正在编辑父模型上的字段。达到此目的的方法是by using #fields_for(特别是“一对多”部分)。

因此,您将按照以下方式进行操作(代码下方的解释):

<% @chapter.users.each_with_index do |chap_user, i| %>
  <%= form.fields_for :users, chap_user do |user_fields| %>
    <div class="row">
      <div class="col-md-4 col-md-offset-4  col-xs-8 col-xs-offset-2">
        <small>User <%= i+ 1 %></small>
      </div>
    </div>

    <div class="row">
      <div class="col-md-2 col-md-offset-4  col-xs-8 col-xs-offset-2">
        <div class="field form-group">
          <%= user_fields.label 'First Name' %>
          <%= user_fields.text_field :first_name, value: chap_user.first_name,class:"form-control"%>
        </div>
      </div>
      <div class="col-md-2 col-md-offset-0 col-xs-8 col-xs-offset-2">
        <div class="field form-group">
          <%= user_fields.label 'Last Name' %>
          <%= user_fields.text_field :last_name, value: chap_user.last_name, class:"form-control"%>
        </div>
      </div>
    </div>

    <div class="row">
      <div class="col-md-4 col-md-offset-4 col-xs-8 col-xs-offset-2">
        <div class="field form-group">
          <%= user_fields.label :email %>
          <%= user_fields.text_field :email, value: chap_user.email, class:"form-control"%>
        </div>
      </div>
    </div>
  <% end %>
<% end %>

改变的是,我使用#fields_for方法将所有表单输入包装在一个块中,以指定现在我们要修改子属性。这样做时,我们还要指定一个变量名,该变量名将用于为子模型的属性生成字段。我将其命名为user_fields,然后在该块内部将form的所有引用替换为user_fields

在您的ChaptersController中,您希望接受参数的行为:

params.require(:chapter).permit(:city, :country_id, users_attributes: [:id, :first_name, :last_name, :email])

您想要users_attributes而不是user_attribute,因为复数的“用户”告诉rails期望多个孩子(多个用户)的属性。然后,在该数组中,您想告诉它所有期望的字段,包括id。即使您没有为ID明确定义一个字段,Rails也会使用它允许您编辑已经存在的子代的属性(不仅能够创建新的子代)。文档中的摘录:

  

请注意,#fields_for将自动生成一个隐藏字段来存储记录的ID。在某些情况下,不需要此隐藏字段,您可以传递include_id:false以防止#fields_for自动呈现它。

如果有关此操作不起作用,或者您还有其他问题,请随时告诉我!