Rails远程表单参数未传递给控制器

时间:2017-10-24 19:15:25

标签: ruby-on-rails model-view-controller parameters actioncable

我在我的rails应用程序中有一个表单,用户只需输入一个数字,然后使用ajax提交表单。如果存在所有参数,则在我的游戏控制器中创建新游戏。我有两个hidden_​​field_tags,其参数非常好地传递给控制器​​,但最重要的参数,即从用户输入得到的参数,似乎没有传递给控制器​​。

我的表格:

<%= form_for @game, :url => {:controller => "games", :action => "create" }, :html => { :role => 'form' }, remote: true, method: :post do |f| %>
  <div class="row">
    <div class="col-md-4 col-md-offset-4">
      <div class="input-group">
        <%= f.text_field :user_stake, class: 'form-control' %>
        <span class="input-group-btn">
          <%= f.submit 'Go', :html => { :type => "button" }, class: "btn btn-default" %>
        </span>
      </div>
    </div>
  </div>

    <%= hidden_field_tag 'user_id', current_user.id  %>
    <%= hidden_field_tag 'jackpot_id', @jackpot.id  %>

<% end %>

控制器:

 before_action :game_params, only: [:create]

  def create
    @game = Game.new(game_params)
    if @game.save
      @jackpot = Jackpot.find(params[:jackpot_id])
      ActionCable.server.broadcast 'jackpot_channel',
                                        users: Jackpot.where(id: @jackpot.id),
                                        pot: @jackpot,
                                        user: User.find(@game.user_id),
                                        game: @game,
                                        stake: @game.user_stake.to_s
    else
      ActionCable.server.broadcast 'jackpot_channel',
                                        error: @game.errors.full_messages
    end
  end

  def new
    @game = Game.new
  end

  private
    def game_params
      params.permit(:user_stake, :user_id, :jackpot_id)
    end

无论@game中输入的是什么,都会以user_stake为0.0保存,我已将其设置为迁移中的默认值。我不知道我在这里做错了什么。有任何想法吗?谢谢!

2 个答案:

答案 0 :(得分:2)

您可能需要检查服务器日志,以查看正在发布到控制器的创建方法的内容。我怀疑游戏参数是封装在game哈希中的。要访问它,我建议将game_params更改为要求游戏:

def game_params
  params.require(:game).permit(:user_stake, :user_id, :jackpot_id)
end

答案 1 :(得分:2)

您未正确嵌套输入:

<%= form_for @game, html: { role: 'form' }, remote: true %>  
  <%= f.text_field :user_stake, class: 'form-control' %>
  <%= hidden_field_tag 'user_id', current_user.id  %>
  <%= hidden_field_tag 'jackpot_id', @jackpot.id  %> 
  # ..
<% end %>

这将给出以下参数哈希:

{
   game: {
     user_stake: 1.2
   },
   user_id: 3,
   jackpot_id: 4
}

如果您通过白名单发送,则获得:

{
   user_id: 3,
   jackpot_id: 4
}

解决方案是简单地嵌套输入:

<%= form_for @game, html: { role: 'form' }, remote: true %>  
  <%= f.text_field :user_stake, class: 'form-control' %>
  <%= f.hidden_field_tag 'user_id', current_user.id  %>
  <%= f.hidden_field_tag 'jackpot_id', @jackpot.id  %> 
  # ..
<% end %>

正确地将它们列入白名单:

private
  def game_params
    params.require(:game)
          .permit(:user_stake, :user_id, :jackpot_id)
  end

但是这里有一个巨大的警告标志 - 从不通过params传递当前用户ID,因为它使得一个恶意用户很容易破解除了网络检查员。而是直接从会话中使用该值。

除了用户密码或了解应用程序密码外,您无法伪造。

此外,如果游戏属于累积奖金,我会将其设置为nested resource并将ID放在路径中,因为这会创建一个RESTful结构,清楚地表明您正在向父资源添加子项 - 而不是将重要信息隐藏在请求体中。

# routes.rb
resources :jackpots do
  resources :games, shallow: true
end
class GamesController
  before_action :set_jackpot, only: [:new, :create, :index]

  # GET /jackpots/:jackpot_id/games/new
  def new
    @game = @jackpot.games.new
  end

  # POST /jackpots/:jackpot_id/games
  def create
    @game = @jackpot.games.new(game_params) do |g|
      g.user = current_user
    end

    if @game.save
      # ...
    else
      # ...
    end
  end

  # GET /jackpots/:jackpot_id/games
  def index
    @games = @jackpot.games
  end

  private 

    def set_jackpot
      @jackpot = Jackpot.includes(:games)
                        .find(params[:jackpot_id])
    end

    def game_params
      params.require(:game).permit(:user_stake)
    end
end
<%= form_for [@jackpot, @game], remote: true, html: { role: 'Form' } do |f| %>
  <div class="row">
    <div class="col-md-4 col-md-offset-4">
      <div class="input-group">
        <%= f.number_field :user_stake, class: 'form-control' %>
        <span class="input-group-btn">
          <%= f.submit 'Go', :html => { :type => "button" }, class: "btn btn-default" %>
        </span>
      </div>
    </div>
  </div>
<% end %>

请注意,不需要隐藏的输入。