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

时间:2014-09-06 21:36:13

标签: 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

我有以下用户模型:

class User < ActiveRecord::Base
  has_one :customer
  accepts_nested_attributes_for :customer, :allow_destroy => true
end

以下客户模型:

class Customer < ActiveRecord::Base
  belongs_to :user
end

最后,这是表格:

<%= 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 %>

当我提交表单时,我看到:`未经许可的参数:客户&#39;在日志中,但似乎我确实允许它。

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

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

2 个答案:

答案 0 :(得分:6)

@Mandeep的答案之后,让我再向您提供一些信息:

  
      
  1. 你需要&#34;建立&#34;您的表单的关联对象
  2.   
  3. 您需要根据模型
  4. 关联进行处理   
  5. 您需要按照所述关联保存属性
  6.   

这样做的方法相对简单(Mandeep概述)。但是,为什么的原因可能不太明显:


<强>构建

首先,您需要建立关联关联。这非常重要,主要是因为Rails(由于构建在Ruby上)是一个object orientated框架。

面向对象,没有太多细节,意味着你使用Rails做的所有将基于对象。对于我们心爱的Rails,这意味着每个Model都是object

凭借这一事实,只要您想创建这样的表单,嵌套模型范例就必须在Rails中构建。要执行此操作,您需要使用build methods - 告诉ActiveRecord(Rails&#39; object relational mapper)您还有另一个要填充的关联模型/对象:

#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

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

-

<强>协会

其次,您需要考虑您拥有的关联。这很重要,因为奇异和多个关联在&#34; build&#34;中的处理方式不同处理。

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

enter image description here

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

enter image description here

这解释了使用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

-

保存

上述控制器代码将保存您需要的属性。

您必须了解传递嵌套属性意味着您要发送关联数据的模型需要从属于您的&#34; main&#34;模型。如最初所讨论的,模型中的ActiveRecord associations会发生这种情况。

希望这能让你更清晰

答案 1 :(得分:4)

将您的代码更改为:

def new
  @user = User.new
  @user.build_customer
end

你的表格:

<%= form_for @user do |f| %>
  // user fields
  <%= f.fields_for :customer do |customer| %> 
    // customer fields
  <% end %>
<% end %>   

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