Reputation: 173
I'm having trouble with what I feel should be a simple issue. I'm trying to create a basic match score reporting app and I'm trying to create a match and the match players simultaneously.
My models:
class Match < ApplicationRecord
has_many :match_players
accepts_nested_attributes_for :match_players
end
class MatchPlayer < ApplicationRecord
belongs_to :player
belongs_to :match
end
My form:
.container
%h1 Log a completed match
= simple_form_for @match do |f|
= f.input :played_at, html5: true
= f.simple_fields_for :match_player do |mp|
= mp.input :player_id, collection: Player.all, label_method: lambda { |player| player.first_name + " " + player.last_name }
= f.submit "Submit Match Score"
My controller action and params:
def create
@match = Match.new(match_params)
if @match.save
player = MatchPlayer.create(player: current_player, match: @match)
opponent = MatchPlayer.create(player: Player.find(match_params[:match_player_attributes][:player_id], match: @match))
else
render :new
end
end
private
def match_params
params.require(:match).permit(:played_at, match_player_attributes: [:player_id])
end
Right now I'm getting a found unpermitted parameter: :match_player
issue. If I change match_player_attributes
to match_player
in my params then I get unknown attribute 'match_player' for Match.
The error is occurring on the first line of the create action (@match = Match.new(match_params)
)
Any help would be appreciated!
Edit following suggestions:
Controller:
def new
@match = Match.new
@match.match_players.build
end
def create
@match = Match.new(match_params)
if @match.save!
player = MatchPlayer.create(player: current_player, match: @match)
opponent = Player.find(match_params[:match_players_attributes]["0"][:player_id])
opponent_match_player = MatchPlayer.create(player: opponent, match: @match)
redirect_to(root_path, notice: "Success!")
else
render :new
end
end
private
def match_params
params.require(:match).permit(:played_at, match_players_attributes: [:player_id])
end
Form:
= simple_form_for @match do |f|
= f.input :played_at, html5: true
= f.simple_fields_for :match_players do |mp|
= mp.input :player_id, collection: Player.all, label_method: lambda { |player| player.first_name + " " + player.last_name }
= f.submit "Submit Match Score"
Now it's creating 3 match_players, one for the current_player and 2 of the opponent. What's going on?
Upvotes: 0
Views: 72
Reputation: 4440
Looks like the problem in the simple typo,
Try to change:
= f.simple_fields_for :match_player do |mp|
to
= f.simple_fields_for :match_players do |mp|
Also
def match_params
params.require(:match).permit(:played_at, match_player_attributes: [:player_id])
end
to
def match_params
params.require(:match).permit(:played_at, match_players_attributes: [:player_id])
end
Here is wiki with examples
UPD: From wiki I shared with, you can find this point:
accepts_nested_attributes_for - an ActiveRecord class method that goes in your model code - it lets you create and update child objects through the associated parent. An in depth explanation is available in the ActiveRecord documentation.
It means that you don't need to create opponent
manually
opponent = Player.find(match_params[:match_players_attributes]["0"][:player_id])
opponent_match_player = MatchPlayer.create(player: opponent, match: @match)
Because when you send your params with nested attributes:
match_players_attributes: [:player_id]
inside of match
creation process match_player
will be created automatically
Upvotes: 1
Reputation: 727
I can see in your model
, you have:
has_many :match_players
hence, in your controller and in your form, you must use match_players
(plural not singular)
Thus, in your controller
, you will have:
def match_params
params.require(:match).permit(:played_at, match_players_attributes: [:id, :player_id])
end
And, in your form
:
...
= f.simple_fields_for :match_players do |mp|
...
Notice the last s of match_player in form and in controller.
Upvotes: 1