Rails嵌套表单不保存嵌套属性

gha*_*hal 6 ruby-on-rails ruby-on-rails-4

我有以下用户控制器:

class UsersController < ApplicationController

  def index
    @users = User.all
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    @customer = Customer.new

    if @user.save
      flash.notice = "User '#{@user.email}' was succefully created."
      redirect_to user_path(@user)
    else
      render 'new'
    end
  end

  def show
    @user = User.find(params[:id])
  end

  private

  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation, customer_attributes: [:id, :company])
  end
end
Run Code Online (Sandbox Code Playgroud)

我有以下用户模型:

class User < ActiveRecord::Base
  has_one :customer
  accepts_nested_attributes_for :customer, :allow_destroy => true
end
Run Code Online (Sandbox Code Playgroud)

以下客户模型:

class Customer < ActiveRecord::Base
  belongs_to :user
end
Run Code Online (Sandbox Code Playgroud)

最后,这是表格:

<%= form_for [@user] do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :email %><br>
    <%= f.text_field :email %>
  </div>
  <div class="field">
    <%= f.label :password %><br>
    <%= f.password_field :password %>
  </div>
  <div class="field">
    <%= f.label :password_confirmation %><br>
    <%= f.password_field :password_confirmation %>
  </div>
  <%= f.fields_for :customers do |company| %>
    <div class="field">
      <%= company.label :company %><br>
      <%= company.text_field :company %>
    </div>
  <% end %>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
Run Code Online (Sandbox Code Playgroud)

当我提交表单时,我看到:"未经许可的参数:客户"在日志中,但似乎我确实允许它.

另外,我想在show和index视图中显示每个用户的公司名称.我不知道该怎么做.

我记得build过去使用这种方法来获得类似工作的东西,但这次我似乎无法弄明白.

Ric*_*eck 7

继续@Mandeep回答,让我给你一些进一步的信息:

  1. 您需要为表单"构建"关联对象
  2. 您需要根据模型的关联来处理此问题
  3. 您需要按照所述关联保存属性

这样做的方法相对简单(概述Mandeep).然而,原因为何可能会有点不太明显:


建立

首先,您需要建立关联关联.这非常重要,主要是因为Rails(基于Ruby构建)是一个面向对象的框架.

面向对象,没有太多细节,意味着你使用Rails做的每件事都将基于对象.在我们心爱的Rails的情况下,它意味着每一个Model都是一个object.

凭借这一事实,只要您想创建这样的表单,就必须在Rails中构建嵌套模型范例.要做到这一点,你需要使用这些build方法 - 它告诉ActiveRecord(Rails的对象关系映射器)你有另一个你想要填充的关联模型/对象:

#app/controllers/users_controller.rb
class UsersController < ApplicationController
   def new
      @user = User.new #-> initializes "User" object
      @user.build_customer #-> "builds" the associated object
   end
end
Run Code Online (Sandbox Code Playgroud)

这为Rails提供了一组可以填充表单的相关数据(考虑到你调用了正确的方法)

-

协会

其次,您需要考虑您的关联.这很重要,因为在"构建"过程中处理单一和多个关联的方式不同.

您正在使用has_one关系,这意味着您需要使用单一的关联名称(尽管您可以随意调用关联):

在此输入图像描述

如果您使用了has_many关联,则需要使用复数关联方法:

在此输入图像描述

这解释了使用该build_customer方法的必要性; 但也应该给你用奇异的关联名称,你需要得到这个工作,即所有方法遵fields_forparams:

#app/views/users/new.html.erb
<%= form_for @user do |f| %>
  ...
  <%= f.fields_for :customer do |c| %>
      ...
  <% end %>

  <%= f.submit %>
<% end %>

#app/controllers/users_controller.rb
class UsersController < ApplicationController
   def create
      @user = User.new user_params
      @user.save
   end

   private

   def user_params
      params.permit(:user).permit(:user, :params, customer_attributes: [:x. :y])
   end

end
Run Code Online (Sandbox Code Playgroud)

-

保存

以上控制器代码将保存您需要的属性.

您必须了解传递嵌套属性意味着您要发送关联数据的模型需要从属于"主"模型.ActiveRecord associations如最初所讨论的那样,这会发生在您的模型中.

希望这能让你更清晰


Man*_*eep 4

将您的代码更改为:

def new
  @user = User.new
  @user.build_customer
end
Run Code Online (Sandbox Code Playgroud)

您的表格:

<%= form_for @user do |f| %>
  // user fields
  <%= f.fields_for :customer do |customer| %> 
    // customer fields
  <% end %>
<% end %>   
Run Code Online (Sandbox Code Playgroud)

您的创建方法中也不需要 @customer = Customer.new 。