简体   繁体   中英

Ruby on Rails, undefined method merge

At the beginning let me excuse for easy question for those who are experienced but for me it is difficult right now. In the Rails in one of the views/_form.html.erb, I want to change line below (it works):

    <%= f.collection_select :user_id, User.all, :id, :email %>

into hidden field that will hold the id of the user that is logged in. I try to change it into:

    <% f.hidden_field :user_id, :id %>

but it throws an error:

    NoMethodError in Orders#new
    undefined method `merge' for :id:Symbol

Can sb help me to solve that?

This error means that it expects a hash, but you are putting an empty symbol.

You need to send a hash

If you have the current_user method:

<%= f.hidden_field :user_id, :value => current_user.id %>

If you don't, you may use this in your controller

   id = User.find(someid)

And keep the same code in the view.

Look @ the documentation for more info

The first two answers are correct. Here's why

f.hidden_field is a method on the form object you created somewhere either in that partial or in a file/partial that includes it. The documentation linked by Hristo Georgiev is for the hidden_field method from ActionView::Helpers::FormHelper ( link ). The one you're trying to call is from ActionView::Helpers::FormBuilder ( link )

hidden_field works just as you seem to be expecting it to, ie

hidden_field(:user_object, :id)

these are two different methods

f.hidden_field works a bit differently, because it already has access to some of the information used to build the hidden field. It expects a method to call on the form object and an optional hash which it converts to attributes on the hidden field (thus the :value => user.id hash)

Assuming you had the following form

form_for(@user) do |f|
  ...
end

And you wanted the id to be a hidden field, you would put this within that block

f.hidden_field(:id)

That would generate the following HTML

<input type="hidden" id="user_id" name="user[id]" value="1" />

See this line from ActionView

TL;DR

You're calling the FormBuilder#hidden_field method with the arguments expected by FormHelper#hidden_field

Use this (if you already have current_user method available):

<%= f.hidden_field :user_id, :value => current_user.id %>

If you don't have current_user method implemented, in your corresponding controller, you can have something like this:

@current_user = User.find(params[:user_id])

Then, in your view, you can do:

<%= f.hidden_field :user_id, :value => @current_user.id %>

Update

After the above conversation, if you want to use session to store the user_id, then you can do something like this.

You can create a SessionsHelper module (which you can include in your ApplicationController ) where you can define a log_in method:

  # Logs in the given user.
  def log_in(user)
    session[:user_id] = user.id
  end

(You can also put this: session[:user_id] = user.id in the create action where you create an user.)

You can also define a current_user method in this module:

  # Returns the current logged-in user (if any).
  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end

Here are some other useful helper methods that you can add in this module:

  # Returns true if the given user is the current user.
  def current_user?(user)
    user == current_user
  end

  # Returns true if the user is logged in, false otherwise.
  def logged_in?
    !current_user.nil?
  end

  # Logs out the current user.
  def log_out
    session.delete(:user_id)
    @current_user = nil
  end

Finally, I would suggest you to take a look at Devise gem which is a very popular authentication solution for Rails application.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM