How do I pass form variables from views to controllers in Rails 4? - forms

I'm trying to accept telephone numbers in a simple form and I can't seem to get it to pass the variable through to the controller. The code I have so far is:
view on /users/new.erb:
<%= form_for #user do |f| %>
<%= field_set_tag do %>
<p><%= f.label :phone %><br>
<%= f.text_field :phone%>
<%= f.submit "Submit" %>
<% end %>
<% end %>
and in the controller I have:
def new
#user = User.new
end
def create
#user = User.new(params[:new])
phone = #user.phone
end
Any help would be greatly appreciated. Thanks.

There are a few problems with your code. When you write:
<%= form_for #user %>
All the form fields are sent to the controller in the form of a hash with "user" as the root. Just like
{"user": {"phone": "ENTERED PHONE NUMBER"}}
To access these fields in the controller you need to use the following method:
#phone_number = params[:user][:phone]
One More Important Thing
For security purposes rails does uses Strong Parameters. It means that you can't use the form parameters directly in Active Model for mass assignment like this:
#user = User.new(params[:user])
You need to permit all the fields explicitly for mass assignment. This can be achieved as follows.
def create
#user = User.new(params_user)
#user.save
end
private
def params_user
params.require(:user).permit(:phone)
end

params[:new] just passes the parameter :new to your #user object, but there is no params[:new] parameter because it is not defined in your form. params[:phone] should be passed to '#user' just params if you want all available params that were submitted.
Try
#user = User.new(params) #instead of #user = User.new(params[:new])
#user.phone

Related

form_for does not pass the required value when user submits blank form [duplicate]

This question already has answers here:
Rails 4: How do I handle a submitted form where nothing was selected?
(3 answers)
Closed 7 years ago.
I have the following form:
# controller
def edit
#doc = HomeworkDocument.find(params[:id])
end
# view
<%= form_for #doc,
url: student_homework_document_path(student_id: #doc.submitter_id,
id: #doc.id),
html: { multipart: true } do |f| %>
<%= f.label :file1 %>
<%= f.file_field :file1 %>
<%= f.label :file2 %>
<%= f.file_field :file2 %>
<%= f.submit "Submit" %>
When the user submits either one or both of file1 and file2, the form works fine. However, when the user clicks submit without any file, exception is raised:
param is missing or the value is empty: homework_document
due to my strong param specification:
def doc_grader_params
params.require(:homework_document)
.permit(:file1, :file2)
end
The param that gets passed is (notice no homework_document is passed):
Parameters:
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"QJirOW/HQ3sv8AR/yArW6cQ2bmvz0j5D8G6czu45lLA=",
"commit"=>"Submit grading",
"student_id"=>"4",
"id"=>"21"}
Why does this happen and how to to include an (empty) homework_document hash in param even when the user submits blank form?
To include an empty homework_document hash, you have two options:
Assuming you do not want to override the :file1, :file2 attributes if submission is empty, add an empty hidden_field in the form and allow that to pass in via strong parameters, but do virtually nothing to the parameter. Like so:
<%= hidden_field_tag 'homework_document[placeholder]', 'do nothing' %>
def doc_grader_params
params.require(:homework_document)
.permit(:file1, :file2, :placeholder)
end
If you do want to override the attributes (erasing files if empty), place two hidden_fields of name homework_document[file1] and homework_document[file2] before the file inputs and set their value to ''(or whatever defaults you have). Because parameters extraction gets the last occurrence of any repeated key in the query string, this should work.
This approach is similar to the check_box empty submission approach outlined in:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-check_box

Rails 4: undefined method `permit' for "xxxx xxxx":String

I have a search model that I hope to use in conjuction with sunspot to handle all searches across different models. I'm stuck before I even have gotne started.
Here is the form...that appears in the header of all the web pages on my site.
<%= simple_form_for #search, :url => searches_path, :method => :post do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", class: "btn btn-primary" %>
<% end %>
In my searches_controller
def search_params
params.require(:search).permit(:search)
end
In my Search.rb
attr_accessor :search
When I plug in my name into it I get this error
undefined method `permit' for "simon walsh":String
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"1Tez0pnMILEciLR6j+li+qSeO4NYBj3XsB6dYG07RymsiNUNSAGI5ztpMiD4JNAtTnqwJYdHTpPBRqGduWHjBw==",
"search"=>"simon walsh",
"commit"=>"Search"}
I am confused. This is clearly a simple error with the way I am posting the params. Any help?
Use this:
def search_params
params.require(:search).permit!
end
Instead of this:
def search_params
params.require(:search).permit(:search)
end
This issue may occur because of string parameter in params["search"], while in controller you are using .permit(:search), or maybe you have an attribute and model name that are the same.

Why is my date_field parameter nested inside the label name?

in my controller, I have this:
def index
filter = []
if !params[:paid].blank?
paid = params[:paid]
filter << ["copay_received = '#{paid.to_s}'"]
end
if !params[:junk].blank?
junk = params[:junk][:effective_on]
filter << ["clients.effective_on >= '#{junk.to_s}'"]
end
#unpaids = Appointment.joins(:client).where(filter.join(" AND "))
end
which is based on the (non-accepted) answer to this question.
Here is the form I used on the index page to search it:
<%= form_tag("/", method: "get") do %>
<%= label_tag(:paid, "Search for:") %>
<%= check_box_tag(:paid) %>
<%= date_field(:junk, :effective_on) %>
<%= submit_tag("Search") %>
<% end %>
I finally got my date_field working (as shown with the effective_on parameter).
But my question is why do I have to go an extra layer down into the params hash to get :effective_on while I don't have to do the same thing to reach :paid?
you are using the wrong method. it should be date_field_tag.
the date_field method is supposed to be used with an object form like
form_for #user do |f|
f.date_field :born_on
end

Rails: how to save few elements from string

I have rails form_tag helper to save data provided by do..each loop. This is my form:
<%= form_tag (customers_path) do |f| %>
< #contacts.each do |c|%>
<%= check_box_tag "accept[]", c %><%= c[:email] %>
<% end %>
<%= submit_tag ("Save") %>
<%end%>
This form saves the contacts whose checkbox is checked. Here is what, c has:
"accept"=>["{:id=>\"2f310f1d9b8f\",
:first_name=>\"San\",
:last_name=>\"Jori\",
:name=>\"Jori,San\",
:email=>\"abc#qwe.com\",
:gender=>nil,
:birthday=>nil,
:profile_picture=>nil,
:relation=>nil}"],
"commit"=>"Save"
I want to save only :name and :email from above hash.
This is my create action of controller:
if params[:accept].present?
params[:accept].each do |customer|
#customer = current_user.customers.new(:name => customer[:name], :email => customer[:email])
#customer.save
end
redirect_to customers_path
end
But it is giving error of :
no implicit conversion of Symbol into Integer
Can anyone tell me how to make it work?
Thank you!
Instead of using
#customer = current_user.customers.new(:name => customer[:name], :email => customer[:email])
Try
#customer = current_user.customers.build(:name => customer[:name], :email => customer[:email])

Rails Tutorial 3.2 Chapter 8 error: NoMethodError in SessionsController#create

I'm going through the rails tutorial and my login page is throwing an exception after exercise 8.1.5 when I click the login button with no email or pw entered:
http://ruby.railstutorial.org/chapters/sign-in-sign-out#sec-rendering_with_a_flash_message
Error:
NoMethodError in SessionsController#create
undefined method `[]' for nil:NilClass
app/controllers/sessions_controller.rb:7:in `create'
SessionsController matches the final code exactly for the Create method
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email].downcase) #line 7
if user && User.authenticate(params[:session][:password])
#will fill this in later
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
end
end
I did change the button label to Log in instead of "Sign in" as that is too confusing with "Sign up", but I didn't think that would create the problem. sessions\new.html.erb
<% provide(:title, "Log in") %>
<h1>Log in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:sesssion, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Log in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
This post hints that I need a method in my user model, but adding that didn't help:
NoMethodError in SessionsController#create
I tried adding this to user.rb, but it didn't help
results from find_by_email executed in function differs from console:
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return user.nil? ? nil : user
end
Any ideas would be greatly appreciated!
I've looked at the example from the book and your code and I noticed this line
if user && User.authenticate(params[:session][:password])
your User.authenticate should be lowercased to user.authenticate. Revert back to your original code.
I have just had the same problem and found that in fact i needed [:sessions] with an s on the end!
So line reads
if user && User.authenticate(params[:sessions][:password])
Hope this helps someone in the future!
I had the same problem after doing exercise 1 in chapter 8 where I replaced the use of form_for with form_tag. This resulted in the name attributes in the generated input form fields changing from name="session[email]" and name="session[password]" to name="email" and name="password". Subsequently, I needed to access the params using params[:email] and params[:password] instead of params[:session][:email] and params[:session][:password].
My new Sessions controller looks like this:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email].downcase)
if user && user.authenticate(params[:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
sign_out
redirect_to root_url
end
end
This solved the problem for me. Hope this is helpful to someone else.
In this section from the tutorial chapter 8, all instances of [:session] should be [:sessions]. Hope that helps.
class SessionsController < ApplicationController
.
.
.
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
.
.
.
end
Could you confirm the word 'session' in app/view/session/new.html.erb spelling correct?
I see you wrote:
form_for(:sesssion, url: sessions_path) do |f|
But in app/controllers/sessions_controller.rb, you wrote:
user = User.find_by_email(params[:session][:email].downcase) #line 7
They must be the same.