1

I'm really confused on when to use hidden fields.

I'm trying to pass the user_id when submitting a form, other than:

<%= f.hidden_field :user_id %> 

However, I know this is wrong. I've set the model to belong to user but as far as I can tell, that doesn't auto assign the ID.

Can someone point me in the right direction?

EDIT: Thanks for the responses everyone. As I stated before, I know you shouldn't use hidden_field for something important like ID. Mass assignment is too easy this way, as per the link @brad-werth post.

I'm adding code to make this a little easier to answer. I need to submit the form below and make sure that it's assigned to a user. Also, yes, I'm using Devise:

votes_controller.rb

class VotesController < ApplicationController
  before_action :set_vote, only: [:show, :edit, :update, :destroy]

# GET /votes
# GET /votes.json
def index
  @votes = Vote.for_user(current_user).where(nil)
end

# GET /votes/1
# GET /votes/1.json
  def show
   redirect_to action: "index"
  end

# GET /votes/new
 def new
  @vote = Vote.new

  if @vote.save
    user_id = current_user.id
  else
    render 'new'
  end
 end

_form.html.erb

<%= form_for(vote) do |f| %>
  <% if vote.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(vote.errors.count, "error") %> prohibited this vote from being saved:</h2>

      <ul>
        <% vote.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

<div class="field">
  <%= f.label :widget %>
  <%= f.text_field :widget_name, data: {autocomplete_source: widgetnames_path} %>
</div>

<div class="">
  <!-- description will go here -->
</div>

<div class="field">
  <%= f.label :originality %>
  <%= f.number_field :originality %>
</div>

<div class="field">
  <%= f.label :interest %>
  <%= f.number_field :interest %>
</div>

<div class="field">
  <%= f.label :rating %>
  <%= f.number_field :rating %>
</div>

<div class="field">
  <%= f.label :comments %>
  <%= f.text_field :comments %>
</div>

<div class="actions">
  <%= f.submit %>
</div>
<% end %>
Creedian
  • 23
  • 1
  • 7
  • Can you give more details about the form you are using – Sajin Mar 14 '17 at 04:00
  • Hi and welcome to Stack Overflow. Can you provide some of the supporting code eg the controller action(s) (both the one that renders the form and the one that accepts the values submitted). Where do you decide which user-id is going to be used? can you provide more of the `form` so that we can see what it is a form *for*, etc – Taryn East Mar 14 '17 at 04:02
  • http://stackoverflow.com/questions/5163775/is-the-use-of-hidden-fields-in-forms-insecure – Brad Werth Mar 14 '17 at 06:34

4 Answers4

1

If you have an association you can just build the association on User.

current_user.build_profile(profile_params)

This will auto-assign the user_id and you don't need to send any hidden field.

The problem with hidden_field is if I change the value of that field your model or controller has no way to identify that.

Deepak Mahakale
  • 22,834
  • 10
  • 68
  • 88
  • Hey @deepak-mahakale, can you elaborate on your code here? Are you creating a method called build_profile? – Creedian Mar 15 '17 at 00:32
  • You have no control over a user changing the id in the action url either. Stop hiding behind false security. – coreyward Mar 15 '17 at 01:02
  • @coreyward `current_user` usually comes as the result of authentication, not an id in the url. In this context, this solution seems like the ideal way to address ensuring modifications are done only to the current user... It is very similar to your approach of `Vote.new(vote_params.merge(user_id: current_user.id))`, but from the perspective of the user, not the vote. – Brad Werth Mar 15 '17 at 19:06
  • @BradWerth This is what I was responding to, not the use of `current_user`: “The problem with hidden_field is if I change the value of that field your model or controller has no way to identify that.” – coreyward Mar 15 '17 at 23:35
1

Assuming your routes look something like this:

resources :users do
  resources :votes
end

…you handle a path that looks like this:

/users/:user_id/votes

…that routes to VotesController.

If you send a POST request to that path, Rails will route it to the VotesController#create action. That action can access the user_id parameter passed in the URL via the params object, so your action can do something like this:

def create
  @vote = Vote.new(vote_params)
  if @vote.save
    redirect_to user_path(@vote.user_id), notice: :success
  else
    render :new
  end
end

def vote_params
  params.require(:vote).permit(:user_id, :vote_value)
end
protected :vote_params

If, however, a vote is not on a user, but still belongs_to a user, you might have the following routes:

resources :votes

…and a path that looks like this:

/votes

…that routes to your VotesController. In which case, when you POST to this url, you don't have a user_id parameter, but you do have a session object with a way of authenticating the acting user.

In this case, your controller method might look something like this:

def create
  @vote = Vote.new(vote_params.merge(user_id: current_user.id))
  if @vote.save
    redirect_to some_other_path, notice: :success
  else
    render :new
  end
end

def vote_params
  params.require(:vote).permit(:vote_value)
end
protected :vote_params
coreyward
  • 77,547
  • 20
  • 137
  • 166
-1

The relation model does not has attribue user_id, so you can't use like this:

<%= f.hidden_field :user_id %>

If you need to submit user_id, try hidden_field_tag,example:

<%= hidden_field_tag :user_id, @user.id %>
Mohammad Akbari
  • 4,486
  • 6
  • 43
  • 74
tommy
  • 1
  • 2
-1

You need to give it a value. You can set this in your controller.

 <%= f.hidden_field :user_id, value: @user.id %>
  or 
 <%= f.hidden_field :user_id, value: params[:user_id] %>
David Gross
  • 1,863
  • 10
  • 14