添加多条记录到 has_and_belongs_to_many 关系

Add multiple records to has_and_belongs_to_many relationship

我有一个 HABTM 关系设置如下:

class Game < ApplicationRecord
  has_and_belongs_to_many :players
end

class Player < ApplicationRecord
  validates :name, presence: true, uniqueness: true
  has_and_belongs_to_many :games
end

创建新游戏时,我希望用户能够 select 现有玩家添加到游戏中。在 Games#new 视图中我有:

<%= form_with(model: game) do |f| %>
  <h3>Select players participating in this game</h3>

  <% @players.each do |player| %>
    <div class="field">
      <%= check_box_tag :player_ids, player.id, false, { id: "player_#{player.id}"} %>
      <%= label_tag "player_#{player.id}", player.name %>
    </div>
  <% end %>


  <div class="actions">
    <%= f.submit 'Start Game' %>
  </div>
<% end %>

这会向每个用户显示 select 的复选框,但是当多个玩家被 select 编辑并创建游戏时,只有最后一个玩家与游戏相关联。

在我的控制器中

  def new
    @game = Game.new
    @players = Player.all.sort_by &:name
  end

  def create
    @game = Game.new(game_params)

    respond_to do |format|
      if @game.save
        format.html { redirect_to @game }
        format.json { render :show, status: :created, location: @game }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @game.errors, status: :unprocessable_entity }
      end
    end
  end

  private

  def set_game
    @game = Game.find(params[:id])
  end

  def game_params
    params.permit(:player_ids)
  end

我知道我应该附加 player_ids 但我不确定如何附加。

在您的表单中使用收集助手:

<%= form_with(model: game) do |f| %>
  <h3>Select players participating in this game</h3>

  <div class="field">
    <%= f.collection_check_boxes(:player_ids, @players, :id, :name) %>
  </div>

  <div class="actions">
    <%= f.submit 'Start Game' %>
  </div>
<% end %>

然后在您的强参数中,您需要允许一个标量值数组:

class PlayersController
  def new
    @game = Game.new
    # Sort the records in the DB, not in Ruby land.
    @players = Player.all.order(:name)
  end

  def create
    @game = Game.new(game_params)
    respond_to do |format|
      if @game.save
        format.html { redirect_to @game }
        format.json { render :show, status: :created, location: @game }
      else
        format.html do
           # required to render the form
           @players = Player.all.order(:name) 
           render :new, status: :unprocessable_entity 
        end
        format.json { render json: @game.errors, status: :unprocessable_entity }
      end
    end
  end

  private

  def set_game
    @game = Game.find(params[:id])
  end

  def game_params
    params.require(:game)
          .permit(player_ids: [])
  end
end