Несколько объектов с одной формой и разрешающими параметрами - PullRequest
0 голосов
/ 30 ноября 2018

В моем приложении rails есть игровая модель, и в каждой игре несколько игроков.Когда создается игра, создается определенное количество игроков с именем по умолчанию, например:

def create
  @game = Game.new(game_params)
  @game.player_number.times do
    @game.players << Player.new(name: 'Santa')
  end
  if @game.save
    redirect_to action: "players", id: @game.id
  else
    render 'new'
  end
end

Перенаправление приводит пользователя на страницу, на которой есть форма с вводами для имени каждого игрока.Действия, связанные с этой страницей:

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

def playersUpdate
  @game = Game.find(params[:id])
  puts player_params
  if @game.players.update(player_params)
    redirect_to @game
  else
    render 'players'
  end
end

private

def player_params
  params.require(players: [:name])
end

Сама страница редактирования:

<h2> Edit Players </h2>
<%= form_tag({:action => 'playersUpdate'},{:id => @game.id}) do %>
  <%= @game.players.count %>
  <% @game.players.each.with_index do |player,index| %>
    <%= fields_for "players[#{index}]", player do |pl| %>
      <div>
        <%= pl.label :name %><br>
        <%= pl.text_field :name %><br>
        <%= pl.hidden_field :id %>
      </div>
    <% end %>
  <% end %>
  <div>
    <%= submit_tag %>
  </div>
<% end %>

Вот следующие маршруты: rb:

Rails.application.routes.draw do
  get 'welcome/index'

  resources :games do
    collection do
      match "/:id/players" => "games#players", :via => :get
      match "/:id/players" => "games#playersUpdate", :via => :post
    end
  end

  root 'welcome#index'
end

Я получаюошибка:

param is missing or the value is empty: {:players=>[:name]}

И я в растерянности из-за того, что мне не хватает.Любые советы?

Вот параметры, которые передаются, Джордж - это имя, которое я пытаюсь отредактировать, все остальные по умолчанию имеют значение «Санта»:

Processing by GamesController#playersUpdate as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"wNwt9v2ckO/Bl8YGr/a2CDCjSsRec30E51VjZ/Qv2i5BgEnzVbH5M9DsrVfCxdLusS4Ue6Mq+aPSFOiA4K5jJg==", "players"=>{"0"=>{"name"=>"George", "id"=>"122"}, "1"=>{"name"=>"Santa", "id"=>"123"}, "2"=>{"name"=>"Santa", "id"=>"124"}, "3"=>{"name"=>"Santa", "id"=>"125"}}, "commit"=>"Save changes", "id"=>"22"}

1 Ответ

0 голосов
/ 30 ноября 2018

Вы не открываете здесь никаких новых возможностей, и у Rails есть стандартные способы сделать все это.Но легко «сойти с рельсов» и сделать его сложнее, чем нужно.

Концептуально, перестаньте думать об обновлении связки Players и начните думать об обновлении Game, которое происходитиметь немного Players. документы удивительно полезны здесь.

Давайте сначала перейдем к вашей модели игры.Вам нужно будет сказать, что все в порядке, чтобы обновить вложенные атрибуты для игроков, как это:

# models/game.rb

model Game < ApplicationRecord
  has_many :players
  accepts_nested_attributes_for :players
end

Ваше представление генерирует параметры, которые не совсем стандартны.Опять же, пусть Rails сделает всю работу за вас.Вам не нужны скрытые поля или each_with_index.Поскольку мы находимся в Rails 5, давайте использовать новый помощник form_with, и мы позволим fields_for выполнять свою работу, не пытаясь объяснить, как индексировать:

# views/games/edit_players.html.erb

<h2> Edit Players </h2>
<%= form_with(model: game, local: true) do |form| %>
  <div>
    Game name: <%= form.text_field :name %>
  </div>

  <%= form.fields_for :players do |player_fields| %>
    <div>
      Player name: <%= player_fields.text_field :name %><br>
    </div>
  <% end %>

  <div>
    <%= form.submit %>
  </div>
<% end %>

Это сгенерируетпараметры, которые выглядят примерно так:

Parameters: {"game"=>
               {"name"=>"Risk", 
                "players_attributes"=>
                  {"0"=>{"name"=>"Abel", "id"=>"1"}, 
                   "1"=>{"name"=>"Baker", "id"=>"2"}, 
                   "2"=>{"name"=>"Charlie", "id"=>"3"}}}, 
                "commit"=>"Update Game", 
                "id"=>"1"}

Теперь вам даже не нужно настраивать конечную точку обновления.Просто используйте ваше стандартное действие GamesController#update:

# controllers/games_controller.rb

class GamesController < ApplicationController
  ...

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

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

    if @game.update(game_params)
      redirect_to @game
    else
      render :edit
    end
  end

  private

  def game_params
    params.require(:game).permit(:name, players_attributes: [:id, :name])
  end
end

Наконец, ваш файл маршрутов сбивает с толку, потому что вы используете collection (который не ожидает: id) вместо member.Файл маршрутов должен выглядеть примерно так:

# routes.rb

Rails.application.routes.draw do
  resources :players
  resources :games do
    member { get :edit_players }
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...