I have a form in my rails app where a user just enters a number and the form is then submitted with ajax. A new game is created in my gamescontroller if all the parameters are present. I have two hidden_field_tags whose parameters pass to the controller very nicely but the most important parameter, the one gotten from user input, doesn't seem to pass to the controller.
My form:
<%= 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 %>
Controller:
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
No matter what is typed in the @game gets saved with a user_stake of 0.0, which I have set as the default in my migrations. I have no idea what I'm doing wrong here. Any ideas? Thanks!
You may want to inspect your server logs to see what is being posted to your controller's create method. I suspect the game Parameters are encapsulated in a game
hash. To access it, I'd recommend changing game_params
to require game:
def game_params
params.require(:game).permit(:user_stake, :user_id, :jackpot_id)
end
You're not nesting the inputs properly:
<%= 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 %>
This would give the following params hash:
{
game: {
user_stake: 1.2
},
user_id: 3,
jackpot_id: 4
}
If you send that through the whitelist you get:
{
user_id: 3,
jackpot_id: 4
}
On solution is to simply nest the inputs:
<%= 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 %>
And whitelist them properly:
private
def game_params
params.require(:game)
.permit(:user_stake, :user_id, :jackpot_id)
end
But there is a huge warning flag here - NEVER pass the current user id through the params as it makes it really easy for a malicous user to hack with nothing but the web inspector. Instead use the value directly from the session.
You can't fake that except with the users password or by knowing the application secret.
Also if a game belongs to a jackpot I would set it up as a nested resource and put the id in the path as this creates a RESTful structure that clearly shows that you are adding children to a parent resource - instead of hiding that vital information in the request body.
# 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 %>
Note how there are no hidden inputs required.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.