我的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"}
答案 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