Rails4中的嵌套简单表单 - 有很多通过,保存多个记录

ahn*_*cad 3 ruby-on-rails nested-forms has-many-through simple-form

通过关系,我有一个标准的has_many.人类通过连接表交互有许多兽人.互动只是一个表格和模型; 没有控制器或视图.

使用Rails 4中的simpleform gem,我想从人体页面创建一个表单,以便从所有兽人的池中选择多个兽人.提交后,我希望它在交互表中创建/更新尽可能多的记录,每个记录都包含人工ID,并且选择了多个orc ID.:

AKA列表符号

  1. 从一端制作表格(人类)
  2. 列出表格中的所有兽人
  3. 从该列表中选择多个兽人
  4. 将多个记录保存到交互表中,human_id并且orc_id从该列表中选择兽人.(human_id在这些记录中将是相同的,因为它从给定的人类表单页面开始)

我将尽可能多地编写整个故事的代码.请随时要求澄清,并解决任何错误,以实现这一点.

humans
  integer "id"

interactions
  integer "human_id"
  integer "orc_id"


  index ["human_id", "orc_id"] 
  # This is the primary key. no normal id.
  # Is it better to have a primary id for this join table, or does it not matter?

orcs
  integer "id"
Run Code Online (Sandbox Code Playgroud)

楷模

/models/human.rb

class Human < ActiveRecord::Base
  has_many :interaction
  has_many :orcs, through: :interactions

  accepts_nested_attributes_for :interactions
end
Run Code Online (Sandbox Code Playgroud)

/models/interaction.rb

# Purely a join model and table. No controller, no scaffold.
class Interaction <ActiveRecord::Base
  belongs_to :human
  belongs_to :orc

  accepts_nested_attributes_for :orc 
  # Singular to match what was specified in the belongs_to relationship?
  # Do I even need this if I'm only trying to read orcs to save their id into the interactions table, and not trying to modify orcs?
end
Run Code Online (Sandbox Code Playgroud)

/models/orc.rb

class Orc< ActiveRecord::Base
  has_many :interactions
  has_many :humans, through: :interactions

end
Run Code Online (Sandbox Code Playgroud)

控制器

/controllers/humans_controller.rb

class HumansController < ApplicationController

  before_action :set_human,         only: [:show, :edit, :update, :destroy]
  before_action :build_interaction, only: [:new, :edit]

  private
    def set_human
      @human = Human.find(params[:id])
    end

    def human_params
      params.require(:human).permit(
                                    interaction_attributes: [:human_id, 
                                                             :orc_ids,   # Is plural here correct?
                                                             :_destroy]
      )
    end

    def build_interaction
      @interaction = @human.interactions.build
                     # Is the human instance variable valid here?
                     # How many interactions are being built here?
                     # How do I ensure there are as many interaction builds as there will be selected orcs (i.e. as many interaction records to be saved or updated)?
    end
end
Run Code Online (Sandbox Code Playgroud)

/controllers/orcs_controller.rb

class OrcsController < ApplicationController

  before_action :set_orc,   only: [:show, :edit, :update, :destroy]

  private
    def set_orc
      @orc = Orc.find(params[:id])
    end

    def orc_params
      params.require(:orc).permit()
    end

end
Run Code Online (Sandbox Code Playgroud)

查看

/views/humans/_form.html.haml

= simple_form_for(@human, html: { multipart: true }) do |f|
  = f.simple_fields_for :interactions do |i|
    = i.hidden_field :human_id, value: @human.id
    = i.association :orc, collection: Orc.all
                    ^                        
                    # Should this be :orc_id?
                    # Does this code automatically extract the orc_id when saving to the interactions table?
Run Code Online (Sandbox Code Playgroud)

谢谢.

我错过了什么?当我提交时,我确认在交互连接表中没有创建记录.

我认为有些挑战是

  1. 重复使用单个隐藏输入字段创建多个记录.
  2. 当交互表必须是单个orc时获取一个兽人列表(因为它是在交互模型中使用belongs_to:orc定义的)

另外,在哪里可以找到更多关于如何使用复数形式的模型ID的工作(即简单地使用orc_ids代替orc_id,以及具体的后果)?

Xav*_*ier 5

事实证明,simple_form这实际上相当简单(谁知道?).它处理所有中间表的魔力(与Rails的真棒一起).你需要做的就是:

= simple_form_for(@human, html: { Pmultipart: true }), do |f|
  = f.association :orcs
Run Code Online (Sandbox Code Playgroud)

我真的没有使用HAML所以我以前不确定这个逗号do |f|.以下是我在ERB HTML中要说的内容

<%= simple_form_for(@human) do |f| %>
  <%= f.association :orcs %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

然后在您的控制器的param清洁剂中:

def orc_params
  params.require(:orc).permit(orc_ids: [])
end
Run Code Online (Sandbox Code Playgroud)

最后在你的模型中:

class Human < ActiveRecord::Base
  ...
  accepts_nested_attributes_for :orcs
end
Run Code Online (Sandbox Code Playgroud)

就是这样!它将自动创建连接对象.难道你不爱魔术吗?

这将生成由所有兽人填充的多选字段.您可以使用,轻松地将其更改为复选框f.association :orcs, as: :check_boxes.