【问题标题】:Saving multiple records with a single form in Rails 4在 Rails 4 中使用单个表单保存多个记录
【发布时间】:2014-05-15 08:53:26
【问题描述】:

我有一个模型叫Family,它是belongs_to :user 我想让用户在一个表单中添加多个家庭成员,在/views/families/new.html.erb

  • 因此用户会看到一个表单,用于为一个 user_id 创建 3 个家庭成员
  • 将数据输入 3 个相同的表单,然后点击提交
  • 提交一次后,3 个单独表单的数据应在数据库中保存为 3 个不同的记录
  • 现在,当我提交表单时,数据库中的所有值都保存为 NULL。
  • 我做错了什么?我不应该使用强参数吗?

编辑:抱歉,我应该早点提供更详细的代码 稍作修改后的代码

# config/routes.rb
resources :families
#app/models/user.rb 
class User < ActiveRecord::Base
  has_many :families
end
#app/models/family.rb
class Family < ActiveRecord::Base
  belongs_to :user
end
#app/controllers/families_controller.rb
class FamiliesController < ActiveRecord::Controller
  def new
  end
  
  def create
    @family = Family.new(family_params)
    a = params[:family][:"0"]
    @family.user_id = current_user.id
    if @family.save
      flash[:notice] = params[:family][:"0"]
      redirect_to dummy_path
    else
      flash[:notice] = "didnt happen"
    end
  end
  
  private
  
  def family_params
    params.require(:family).permit(:all)
  end
end
#app/views/families/_form.html.erb
<%= form_tag(controller: "families") do %>
  <% i = 0 %>
  <% 3.times do %>
    <br>
    <h2>Family Member # <%= i+1 %> : </h2>
    <br>
    <%= fields_for("family[#{i}]") do |f| %>
        <%= f.text_field :name, class: "form-control" , placeholder: "Name"%> <br>
        <%= f.text_field :relationship, class: "form-control" , placeholder: "Relationship" %> <br>
        <%= f.date_field :dob, class: "form-control" %> <br>
        <%= f.text_field :blood_group, class: "form-control", placeholder: "Blood group" %> <br>
        <%= f.text_field :email, class: "form-control", placeholder: "Email" %> <br>
        <%= f.number_field :phone, class: "form-control", placeholder: "Phone number" %> <br>
        <%= f.text_area :hobbies, class: "form-control", placeholder: "Hobbies" %> <br>
        <% i=i+1 %>
    <% end %>
    <hr>
  <% end %><br>
  <%= submit_tag "Submit", class: "btn btn-primary" %> <br>
<% end %>

【问题讨论】:

  • 你的用户表的属性是什么?
  • :email, :password_digest 加上 rails 创建的那些。但我在这里没有以任何方式使用用户模型,我只想用一个表单在“家庭”表中输入多条记录

标签: ruby-on-rails ruby-on-rails-4


【解决方案1】:

您想使用nested forms。您应该能够复制并粘贴以下代码以开始操作:

app/models/family.rb

class Family < ActiveRecord::Base
  has_many :users

  accepts_nested_attributes_for :users
end

app/models/user.rb

class User < ActiveRecord::Base
  belongs_to :family
end

app/views/families/new.html.erb

<%= form_for(@family) do |f| %>
  <%= f.fields_for :users do |user| %>
    <p>
    <%= user.text_field :name %><br>
    <%= user.text_field :email %>
    </p>
  <% end %>

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

app/controllers/families_controller.rb

  [...]

  def new
    @family = Family.new
    3.times { @family.users.build }
  end

  [...]

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_family
      @family = Family.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def family_params
      params.require(:family).permit(:name, users_attributes: [ :name, :email ])
    end

【讨论】:

  • 一个用户怎么可能有多个家庭?我认为这个问题缺少模型的代码。
  • 抱歉之前的代码太少了。我已经用更多信息更新了问题,非常感谢您的帮助
【解决方案2】:

我一直这样做的方式是做一个新动作update_multiple。这需要具有以下结构的参数(使用您的家庭示例,并更新两条记录,id 为 123 和 456)

params = {:families => {123 => {:name => "foo", :address => "bar"}, 456 => {:name => "baz", :address => "qux"} }}

动作是这样的:

@families = []
params[:families].each do |id, attributes|
  if family = Family.find_by_id(id)
    family.update_attributes(attributes)
    @families << family
  end
end

为了设置具有所需结构的参数,您的表单将设置如下:

<% @families.each do |family| %>
  <div class="family">
    <label>Name: <%= text_field_tag "families[#{family_id}][name]", family.name %></label>
    <label>Address: <%= text_field_tag "families[#{family_id}][address]", family.address %></label>
  </div>
<% end %>

您可以更改 update 操作的结构,而不是执行新操作,如果它获得 params[:family],则执行标准代码,如果获得 params[:families],则执行上述代码。

【讨论】:

  • 就最佳实践的观点而言,这是解决您编写代码方式的好方法吗?我正在尝试使用您的代码并以ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError): 结束,但只是想确定这种方法是否专业。谢谢。
【解决方案3】:

您需要像这样调整您的代码。假设您在 users 表中有 name 属性。

在您的用户模型中

class User < ActiveRecord::Base
  has_many :families, :dependent => :destroy 
  accepts_nested_attributes_for :families, :allow_destroy => true
end

在你的 users_controller 中

def new
  @user = User.new
  @family = 3.times { @user.families.build } #here
end

你的强参数应该是这样的

def user_params 
  params.require(:user).permit(:name, families_attributes: [:name,:email]) 
end

# users/new.html.erb
<%= form_for(@user) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>
  <%= f.fields_for :familes do |builder| %>
    <%= render 'family_fields', :f => builder %>
  <% end %>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

# users/_family_fields.html.erb
<div>
  <%= f.label :name, "Name" %>        
  <%= f.text_field :name %>
  <br>
  <%= f.label :email, "Email" %>
  <%= f.text_field :email %>
</div>

【讨论】:

    【解决方案4】:

    我更喜欢 gems SlimSimple formCocoon 来进行表单操作。使用 cocoon,您可以add/remove 任意数量的子记录。

    用户模型

    class User < ActiveRecord::Base
        has_many :families, dependent: :destroy 
        accepts_nested_attributes_for :families, reject_if: :all_blank, allow_destroy: true
    end
    

    控制器

    class UsersController < ApplicationController
      def new
        @user = User.new
        @user.families.build # This builds default nested form in cocoon
      end
    
      def create
        @user = User.new(user_params)
        @user.save
      end
    
      private
      def user_params
        params.require(:user).permit(
          :name, :email,
          families_attributes: [:id, :name, :relationship, :_destroy])
      end
    end
    

    表格

    .form
      = simple_form_for(@user) do |f|
    
          = f.input :name, label: false, input_html: { placeholder: 'Name' }
    
          = f.input :email, label: false, input_html: { placeholder: 'Email' }        
    
          .cocoon-form
            = f.simple_fields_for :families do |family|
              = render 'family_fields', f: family
        
          .links
            = link_to_add_association 'Add a member', f, :families
    
      .form-actions
        = f.submit
    

    茧偏_family_fields.html.slim

    .nested-fields
      .form-inputs
        = f.input :name, label: false, input_html: { placeholder: 'Name' }
        = f.input :relationship, label: false, input_html: { placeholder: 'Relationship' }
    
      .remove-instance
        = link_to_remove_association " X ", f
    

    编码愉快! :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-21
      • 1970-01-01
      相关资源
      最近更新 更多