Ruby on Rails, undefined method merge - ruby-on-rails

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?

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.

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

Related

undefined method `permit' for "titleofcoolstuff":String

I am just trying to get two parameters from a view to my controller. I'm using Rails 4.2.x and strong params are killing me.
One param, :query, resolves correctly. However the second param, :location, throws the error in the questions title. I have Googled the issue but everyone's scenario seems to be different and their solutions (relatively) unique.
The view in question is index.html.erb which only contains a simple search form.
<%= form_tag("/searches", action: "create", method: "post") do %>
<div>Job Title</div>
<%= text_field_tag(:query) %>
<div>Location</div>
<%= text_field_tag(:location) %>
<%= submit_tag("Go") %>
<% end %>
The controller in question is searches_controller.rb.
class SearchesController < ApplicationController
def index
binding.pry
end
def show
binding.pry
end
def update
end
def create
#query = search_params["query"].to_s || nil
#location = search_params[:location].to_s || nil
binding.pry
end
def delete
end
private
def search_params
params.require(:query).permit(:location)
end
end
The stack trace points to the search_params method, and shows me that I have the following params in the controller
{
"utf8"=>"✓",
"authenticity_token"=>"DEcTwT/NnSY3S3n25zZGXD+KRZcsRkWj9bmN57AMNivFbMXwHF5Vf/psgzSMkZPBa+OWJgafXYGdW+o5KN3xxg==",
"query"=>"titleofcoolstuff",
"location"=>"milwauke",
"commit"=>"Go"
}
What am I missing?
Strong parameters is for providing a hash of attributes, for example:
<%= form_for #user do |f| %>
## form
<% end %>
This may send parameters like this:
"user" => { "name"=> "Your Name", "age" => "23", "location" => "USA" }
Strong parameters in this case would be instructing rails to process the users hash of attributes and specifically these attributes, like this:
params.require(:user).permit(:name, :age, :location)
In your case, you are passing in individual parameters (not hashes of attributes), so if you want to grab them, you grab them explicitly:
def create
#query = params[:query].to_s || nil
#location = params[:location].to_s || nil
#do something
end
No need for strong parameters to whitelist model attributes here. Hope this helps.
In your case
"query"=>"titleofcoolstuff",
"location"=>"milwauke",
"commit"=>"Go"
since your data are not wrapped with any keys (they are at the root) so you can simply access them using like params[:query].
Whitelisting/Strong params
We need to whitelist params only for mass assignment. like #user.update(user_params) Here, unless the params sent by users in user_params are whitelisted i.e. permitted using .permit method; the update method will throw an exception ActiveModel::ForbiddenAttributes.
In your case since your not updating anything you do not need to create strong params for it.
def create
#query = params["query"].to_s || nil
#location = params[:location].to_s || nil
binding.pry
end
If you are gonna do mass assignment in future you have to whitelist your params
For more info see https://cbabhusal.wordpress.com/2015/10/02/rails-strong-params-whilisting-params-implementation-details/

Rails collection_select does not save all values in params hash

So, I'm trying to implement simple role based authentication system using Rails and I'm having a problem with final step - changing roles.
role is attribute in user table and it has a string type.
Idea is that some users with some privilages have ability to change roles.
Code in view looks like this:
<div>
<%= f.label :role, 'Role' %>
<%= f.collection_select :role, User::ROLES, :to_s, :humanize,
prompt: 'Select role' %>
</div>
update method in users_controller looks like this:
def update
#user = User.find(params[:id])
if #user.update(update_params) #update_params is method that returns permitted parameters
redirect_to #user
else
render :edit
end
end
Problem is that user[role] is empty after submitting a form.
Everything is pretty much made "by the book". Also, I am using Cancan but it's turned off for edit and update with load_and_authorize_resource :except => [:update, :edit].
So, I've found a solution. Since I'm using CanCan and user_params method so CanCan itself can set permitted parameters, my update_params method is ignored.
Solution is to add :role to user_params method.

rails 4 strong params session

I am using a custom passwordless login for my app. A user simply needs to enter their username or email, and then a unique login link with a token is sent to them. They enter their username or email into a simple form :
<%= form_tag request_token_path, id:'login-form' do %>
<%= text_field_tag :user_id %>
<% end %>
This posts to a sessions#request_token method which verifies whether that user exists and then sends along the login link.
def request_token
lookup = session_params[:user_id]
if lookup.include? '#'
#user = User.find_by(email: lookup)
else
#user = User.cached_find(lookup)
end
if #user
#user.send_login_link
redirect_to login_path, notice: "#{#user.username.capitalize} your email was sent!"
else
redirect_to login_path, notice: "Whoops! Looks like #{lookup} is not registered on this site. Please check spelling or signup!"
end
end
My question is that in my SessionsController file I defined the sessions_params
private
def session_params
params.require(:session).permit(:user_id,:auth_token)
end
I know that means that I have to use a session object or in order to pass along the :user_id from the form since I defined :user_id as a param that is on valid as an attribute of a session. I am wondering the correct way to do this. Making a new session object doesn't make sense since that isn't even a model I have but is it safe to just take it from the params?
and instead make lookup = params[:user_id] ?
If you have a session object that responds to user_id attribute, you need to create the form for that object specifically:
<%= form_for #session do |f| %>
<%= f.text_field :user_id %>
<% end %>
If that's not the case, and you need to stick to form_tag, try making the attribute name something that would come up in the controller as a session hash:
<%= text_field_tag "session[user_id]" %>
When you do
params.require(:session)
it means you're requiring your params hash to have a session key, which in turn should have the permitted user_id attribute:
{params: {session: {user_id: "something"}}
And thats why you'd need form_for #session OR the textfield with the suggested "session[user_id]" name

Ruby on rails can't create with params

I have a from created in Ruby on rails. The code the form looks like this:
<%= simple_form_for(#action) do |f|%>
<%= render 'shared/error_messages' %>
<%=f.label :action_name, "Action name"%>
<%=f.text_field :action_name%></br>
<%=f.input :startDate,:as => :datetime_picker, :label =>"Start date"%>
<%=f.input :endDate,:as => :datetime_picker, :label =>"End date"%>
<%=f.label :contentURL, "Content url"%>
<%=f.text_field :contentURL%></br>
<%= f.button :submit, class: "btn btn-large btn-primary" %>
<%end%>
But when I click the submit button I get this error:
undefined method `permit' for "create":String
def action_params
params.require(:action).permit(:action_name, :startDate,:endDate,:contentURL)
All other forms a working ok, I guess it is something really obvious, just can't see it :(
I really appreciate any help, solving this problem.
Thanks!!
EDIT:
Controller code:
def create
action = Action.new(action_params)
if #action.save
flash[:success] = "New Action saved"
redirect_to "/"
else
render 'new'
end
end
private
def action_params
params.require(:action).permit(:action_name, :startDate,:endDate,:contentURL)
end
In Rails 4, you must use Strong Parameters in your controllers. Here's some explanation from the official blog. And some example:
class PeopleController < ActionController::Base
# This will raise an ActiveModel::ForbiddenAttributes exception because it's using mass assignment
# without an explicit permit step.
def create
Person.create(params[:person])
end
# This will pass with flying colors as long as there's a person key in the parameters, otherwise
# it'll raise a ActionController::MissingParameter exception, which will get caught by
# ActionController::Base and turned into that 400 Bad Request reply.
def update
redirect_to current_account.people.find(params[:id]).tap do |person|
person.update_attributes!(person_params)
end
end
private
# Using a private method to encapsulate the permissible parameters is just a good pattern
# since you'll be able to reuse the same permit list between create and update. Also, you
# can specialize this method with per-user checking of permissible attributes.
def person_params
params.required(:person).permit(:name, :age)
end
end
Notice how, in the last lines, under the private keyword, the person_params method is defined, which declares the permitted fields to be assigned by the create and update methods on top. And it's the person_params that is used for updating - the valid example - instead of the raw params array.

Why isn't my sign-in form working in ruby-on-rails?

I have a very rudimentary sign-in form where the user enters in his/her name (First Last).
Here is the code in ERB for the form:
<%= form_for :current_user, url: { :controller => 'application', :action=>'current_user' } do |f| %>
<%= f.text_field :name, placeholder: 'First Last', :id => 'currentUser' %>
<%= f.submit 'Submit', :class => 'btn btn-primary' %>
<% end %>
Here is the action current_user:
def current_user
#current_user = User.find_by_name(params[:current_user][:name])
redirect_to '/calendar'
end
And here is it's route
match 'calendar/signin', to: 'application#current_user', via: 'post'
The form works, I tested it by placing a debugger in the current_user action. When I typed in params it returned the user's name that I had entered in as it should have. But once it went back to the /calendar view #current_user became undefined again. Should I be using something rather than redirect_to '/calendar'? Thanks
As a general rule, you should be calling redirect_to with the appropriate path method, for example:
redirect_to calendar_path
Using a literal URL defeats the purpose of the routing system. You'll need to track down and change all instances of /calendar to something else should that ever change. With the routing method, you can change the presentation, the user-facing URL, from the implementation.
Likewise, you should be using the same path notation in your url argument to form_for. Calling it by controller and action is the older way of doing it and isn't without its share of problems, as the URL it uses is not always what you'd prefer.
Your current_user method only assigns #current_user if it's called, and your form requires #current_user to be defined in advance. If for some reason it isn't called, your form won't work, there's no object. :current_user is a reference to #current_user in the context of the view, where the view automatically inherits instance variables from the controller.
Normally you'd have a method like this:
def load_current_user
#current_user = User.find_by(name: ...)
end
Then you trigger this to load all the time:
before_filter :load_current_user
Normally I create a controller class that requires logins and all the "log-in only" controllers inherit from it. That way you should be reasonably assured you don't have pages that are not properly restricted.
Obviously you'd want to skip this on pages that don't require a login, for example your session controller where you log in:
skip_before_filter :load_current_user, only: [ :new, :create ]

Resources