【问题标题】:Multiple objects with one form and permitting parameters具有一种形式和允许参数的多个对象
【发布时间】:2018-11-29 22:11:28
【问题描述】:

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

【问题讨论】:

  • 您需要非常具体地 require 或 permit 取决于传入参数的外观。在您的服务器日志中,您应该会看到一个 POST 或 PATCH 请求。在其下方您应该看到Processing by YourController#playersUpdate as HTML,在下方您应该看到参数。复制参数并将它们添加到您的问题中。
  • 另外,这不是问题的根源,但您的控制器操作应使用snake_case 命名:players_update 而不是playersUpdate。请参阅style guide 了解更多信息。
  • 我继续添加了您要求的参数。

标签: ruby-on-rails ruby forms


【解决方案1】:

你并没有在这里开辟任何新天地,Rails 有标准的方法来完成这一切。但是很容易“脱离轨道”,让它变得比需要的更难。

从概念上讲,不要再考虑更新一堆Players,而是开始考虑更新恰好有一些Players 的Game。 docs 在这里非常有用。

让我们先来看看你的游戏模型。您需要告诉它可以为玩家更新嵌套属性,如下所示:

# 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    相关资源
    最近更新 更多