Проблема с вложенными атрибутами - PullRequest
0 голосов
/ 19 марта 2020

У меня проблемы с тем, что, по моему мнению, должно быть простой проблемой. Я пытаюсь создать базовое c приложение для составления отчетов о результатах матчей, и я пытаюсь создать матч и игроков матча одновременно.

Мои модели:

class Match < ApplicationRecord
  has_many :match_players

  accepts_nested_attributes_for :match_players
end

class MatchPlayer < ApplicationRecord
  belongs_to :player
  belongs_to :match
end

Моя форма:

.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"

Мой контроллер действия и параметры:

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

Прямо сейчас я получить found unpermitted parameter: :match_player вопрос. Если я изменю match_player_attributes на match_player в моих параметрах, то получу unknown attribute 'match_player' for Match. Ошибка возникает в первой строке действия создания (@match = Match.new(match_params))

Любая помощь будет принята!


Редактировать следующие предложения:

Контроллер:

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

Форма:

= 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"

Теперь создается 3 match_players , один для current_player и 2 для противника. Что происходит?

Ответы [ 2 ]

1 голос
/ 19 марта 2020

Я вижу в вашем model, у вас есть:

has_many :match_players

, следовательно, в вашем контроллере и в вашей форме вы должны использовать match_players ( множественное число, а не единственное )

Таким образом, в вашем controller у вас будет:

def match_params
    params.require(:match).permit(:played_at, match_players_attributes: [:id, :player_id])
end

И в вашем form:

...    
= f.simple_fields_for :match_players do |mp|
...

Обратите внимание на последние s match_player в форме и в контроллере.

1 голос
/ 19 марта 2020

Похоже, проблема в простой опечатке,

Попробуйте изменить:

= f.simple_fields_for :match_player do |mp|

на

= f.simple_fields_for :match_players do |mp|

Также

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

Вот вики с примерами

UPD: Из вики, с которой я поделился, вы можете найти этот пункт:

accepts_nested_attributes_for - метод класса ActiveRecord, который входит в код вашей модели - он позволяет создавать и обновлять дочерние объекты через связанный родительский объект. Подробное объяснение доступно в документации ActiveRecord .

Это означает, что вам не нужно создавать opponent вручную

opponent = Player.find(match_params[:match_players_attributes]["0"][:player_id])
opponent_match_player = MatchPlayer.create(player: opponent, match: @match)

, потому что когда вы отправляете свои параметры с вложенными атрибутами: match_players_attributes: [:player_id] внутри match процесс создания match_player будет создан автоматически

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...