如何在Rails中使用一个表单创建同一模型的非嵌套多个记录?

时间:2016-01-24 07:10:32

标签: ruby-on-rails ruby simple-form

我查看了有关Stack Overflow的相关问题,但我不知道该尝试解决这个问题。

要阐明,

  1. 有三种型号:UserAB
  2. 我知道,
  3. A包含3条记录,每条记录包含p1_namep1_scorep2_namep2_score字段。所以,A看起来像
  4. -----------------------------------------------------------
    id | p1_name | p1_score | p2_name | p2_score
    id | p1_name | p1_score | p2_name | p2_score
    id | p1_name | p1_score | p2_name | p2_score
    -----------------------------------------------------------

    1. BUser提交p1_namep2_name来自A评分的猜测的模型。所以,B看起来像:
    2. ---------------------------------------------------------------------------------
      id | user | a_id | p1_name | p1_score_guess | p2_name | p2_score_guess
      id | user | a_id | p1_name | p1_score_guess | p2_name | p2_score_guess
      id | user | a_id | p1_name | p1_score_guess | p2_name | p2_score_guess
      ---------------------------------------------------------------------------------

      1. B belongs_to AB中的每条记录都由usera_id唯一标识。
      2. 我需要使用视图B为模型new创建一个表单,由其控制器的views/B/new.html.erb操作处理。

        这需要是一个单独的表单,显示3行,每行包含:

          来自模型p1_name
        • A(作为文字)
        • 模仿p1_score_guess
        • B(作为数字字段)
        • 来自模型p2_name
        • B(作为文字)
        • 模仿p2_score_guess
        • B(作为数字字段)

        使用一个提交按钮提交后,需要将3条记录中的每条记录的上述数据提交给控制器,并创建多条B条记录。

        我之前没有在Rails 4.2.5中遇到过这种要求,也不知道如何去做。我一直试图这样做两天,首先使用simple_form,它似乎不支持这个(或者我不能支持),然后是Rails表单。

        这对我来说变得棘手,因为我必须在形式的视图中显示模型p1_name中的p2_nameA以及使用它另外,填充模型BB的控制器需要同时接纳p1_namep2_namep1_score_guessp2_score_guess。由于a_id对于每一行都不同,因此也需要考虑(进一步使我无法想出这一行)。

1 个答案:

答案 0 :(得分:1)

怎么样:

<%= form_for :bs, url: bs_path do |f| %>
  <% @as.each do |a| %>
    <%= f.fields_for "[#{a.id}]", B.new do |afields| %>
      <%= a.p1_name %>
      <%= afields.text_field :p1_score_guess %>
      <%= a.p2_name %>
      <%= afields.text_field :p2_score_guess %>
    <% end -%>
  <% end -%>
  <%= f.submit 'save' %>
<% end -%>

在Controller中,你遍历params [:a_s]

def create
  bs_params.each do |a_id, b_attributes|
    B.create b_attributes.merge(a_id: a_id, user: current_user)
  end
end

def bs_params
  params.require(:bs).permit(allowed_a_s)
end

def allowed_a_s
  Hash[a_ids.map {|id| [id.to_s, [:p1_score_guess, :p2_score_guess]]}]
end

def a_ids
  A.pluck(:id)
end

只是为了向您展示我的测试用例 - 我已经分配了@as:

@as = [A.new(id: 1, p1_name: 'p11', p2_name: 'p12'), A.new(id: 2, p1_name: 'p21', p2_name: 'p22'), A.new(id: 3, p1_name: 'p31', p2_name: 'p32')]

并设置为a_ids static:

def a_ids
  %w[1 2 3]
end

并为bs_params启用了一个调试器,输入1,2,3,4,5,6用于猜测:

=> {
  "1"=>{"p1_score_guess"=>"1", "p2_score_guess"=>"2"},
  "2"=>{"p1_score_guess"=>"3", "p2_score_guess"=>"4"},
  "3"=>{"p1_score_guess"=>"5", "p2_score_guess"=>"6"}
}

更新:由于上面的代码没有检查验证,我再试一次(这次没有测试 - 抱歉):

<%= form_for :bs, url: bs_path do |f| %>
  <% @bs.each do |a, b| %>
    <%= f.fields_for "[#{a.id}]", b do |afields| %>
      <%= a.p1_name %>
      <%= afields.text_field :p1_score_guess %>
      <%= a.p2_name %>
      <%= afields.text_field :p2_score_guess %>
    <% end -%>
  <% end -%>
  <%= f.submit 'save' %>
<% end -%>

在控制器中执行:

def new
  @bs = Hash[a_ids.map { |a_id| [a_id, B.new] }]
end

def create
  @bs = {}
  bs_params.each do |a_id, b_attributes|
    @bs[a_id] = B.new b_attributes.merge(a_id: a_id, user: current_user)
  end
  @bs.values.each(&:valid?) # to ensure, all errors are assigned - and not finding one will stop to check for any other
  if @bs.values.all?(&:valid?)
    @bs.values.each &:save
    redirect_to root_path
  else
    render :new
  end
end

和bs_params,allowod_a_s和a_ids如上