具有一种形式和许可参数的多个对象

时间:2018-11-29 22:11:28

标签: ruby-on-rails ruby forms

我的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 %>

这是routes.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]}

我为我可能会丢失的东西迷茫了。有提示吗?

这里是传入的参数,George是我要编辑的名称,所有其他参数默认为'Santa':

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 :(得分:0)

您在这里没有取得任何新突破,Rails具有完成所有这些操作的标准方法。但是很容易“摆脱困境”并使之变得比原来更难。

从概念上讲,不要再考虑更新一堆Players了,而开始考虑更新碰巧有一些Game的{​​{1}}。 docs在这里很有帮助。

让我们首先进入您的游戏模型。您需要告诉它可以更新播放器的嵌套属性,如下所示:

Players

您的视图所生成的参数不是很标准。同样,让Rails为您完成工作。您不需要隐藏的字段或each_with_index。由于我们在Rails 5中,所以我们使用新的# models/game.rb model Game < ApplicationRecord has_many :players accepts_nested_attributes_for :players end 帮助器,让我们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