Rails形式:带有select的表单中的AssociationTypeMismatch

时间:2018-03-04 17:23:09

标签: ruby-on-rails forms select

我尝试在一个匹配和2个玩家之间建立连接,我们可以从注册的玩家列表中选择玩家:

    
<%= f.label :"Joueur 1" %>
<%= f.select :playerone, @players.collect {|a| [a.name, a.id]} , class: 'form-control' %>

<%= f.label :"Joueur 2" %>
<%= f.select :playertwo, @players.collect {|b| [b.name, b.id]} , class: 'form-control' %>

<%= f.label :Prolongations %>
<%= f.check_box :prolongations %><br />

<%= f.submit yield(:button_text), class: "btn btn-primary" %>

表的架构:使用连接表匹配玩家

create_table "matches", force: :cascade do |t|
    t.boolean "prolongations"
end

create_table "matches_players", id: false, force: :cascade do |t|
    t.integer "match_id", null: false
    t.integer "player_id", null: false
    t.index ["match_id", "player_id"], name: "index_matches_players_on_match_id_and_player_id"
    t.index ["player_id", "match_id"], name: "index_matches_players_on_player_id_and_match_id"
end

create_table "players", force: :cascade do |t|
    t.string "name"
    t.integer "points"
end

在matches.controller中:

class MatchesController < ApplicationController
    attr_accessor :player_id, :playerone, :playertwo

def new
    @match= Match.new
    @players = Player.all
end

def create
    @match = Match.new(match_params)

    @players = Player.all
    if @match.save
        flash[:success] = "Votre match a bien été enregistré !"
        redirect_to @match
    else
        render 'new'
        p "Une erreur existe, veuillez recommencer."
    end    
end

def show
    @match = Match.find(params[:id])
end

private
    def match_params
params.require(:match).permit(:prolongations, :playerone, :playertwo)

end
end

在比赛模型中:

class Match < ApplicationRecord
    has_many :teams , class_name: "Team"
    belongs_to :playerone, class_name: "Player" ,foreign_key: "player_id"
    belongs_to :playertwo, class_name: "Player" ,foreign_key: "player_id"
end

我提交表单时的结果是:

  

播放器(#69852298534200)预期,得到“1”这是一个字符串的实例(#4817000)

{"utf8"=>"✓",
 "authenticity_token"=>".............",
 "match"=>{"playerone"=>"1", "playertwo"=>"3", "prolongations"=>"0"},
 "commit"=>"Enregistrer le match"}

我该如何解决?

1 个答案:

答案 0 :(得分:0)

最简单的解决方法是使用playerone_idplayertwo_id作为参数键(更改输入的名称)。如果使用playerone,则setter期望参数是Player的实例 - 而不是包含id的字符串。

这将解决眼前的问题,但有更好的方法来解决它。

首先设置real many to many association

class Match < ApplicationRecord
  has_many :player_matches, dependent: :destroy
  has_many :players, through: :player_matches
end

class Player < ApplicationRecord
  has_many :player_matches, dependent: :destroy
  has_many :matches, through: :player_matches
end

class PlayerMatches < ApplicationRecord
  belongs_to :player
  belongs_to :match
end

这可以让你避免一个非常棘手的问题,当你设置两个属于同一个表的关联时,关联的记录可以在任一列中:

Match.find_by("(playerone_id = :a OR playertwo_id = :a) AND (playerone_id = :b OR playertwo_id = :b)", a: a, b: b)

是的,这就是你如何查询玩家之间的匹配。加入可能会更加混乱。

通过该设置,您可以通过以下方式将玩家分配给匹配:

@match.player_ids = [1,2]

您正可以使用collection helpers

执行此操作
<%= form_for(@match) do |f| %>
  <div class="field">
    <%= f.label :player_ids, "Select the players" %>
    <%= f.collection_select :player_ids, Player.all, :id, :name, multiple: true %>
  </div>
<% end %>

您在控制器端所要做的就是白名单player_ids

class MatchesController < ApplicationController
  # ...
  def create
    @match = Match.new(match_params)
    # ...
  end

  def update
    if @match.update(match_params)
      # ...
    else
      # ...
    end
  end

  # ...

  private

    def match_params
      params.require(:match).permit(:foo, :bar, player_ids: [])
    end
end