Ruby on Rails Tutorial chapter 9 - ruby-on-rails-3

I am confused by the addition of [:session] to params. It also seems to break my website. Can someone please explain what this does for me?
class SessionsController < ApplicationController
.
.
.
def create
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_back_or user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
.
.
.
end
Error message:
1) Authentication signin with invalid information
Failure/Error: before { click_button "Sign in" }
NoMethodError:
undefined method []' for nil:NilClass
# ./app/controllers/sessions_controller.rb:7:increate'
# (eval):2:in click_button'
# ./spec/requests/authentication_pages_spec.rb:18:inblock (4 levels) in '
EDIT 8/2
I believe the problem is related to a switch from form_for to form_tag. I lost the reference to sessions in the switch because I could not figure out how to properly include it. If anyone has any advice on this issue it would be most appreciated. I am wondering if there is a practical reason for wanting it to be params[:session][:email] instead or is it just for organization?
new.html.erb
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_tag sessions_path do %>
<%= label_tag :email %>
<%= text_field_tag :email %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>

Try removing the [:session] brackets, that worked for me

It brakes your code 'cos the params[:session] is nil I think and you trying to get [:email] from nil, what ofcourse should cause the exception. There should be some code in tutorial that defines params[:session] hash. Try to look better.
To make your code stable you have to be sure that params[:session] is always defined or try to use ternar function params[:session] ? params[:session][:email] : ''

You can replace this in your view :
<%= form_for :session, :url => sessions_path do %>
<%= label_tag :email %>
<%= text_field_tag :email %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
form_tag generate just an HTML form tag and form_for is used to describe something. All the inputs for a field of a form create with form_for will have a name like this : user_session[email]. So, when you submit the form, in your controller, you will have this : params[:user_session][:email].

Related

Registration in Rails

I am attempting to create a new user in rails. There is a username, email, password and password confirm field on the new user form. When I click on the create user button on the web page, the new_user form simply refreshes and the user is not added to the database.
Here is the code for my register method in the authentication controller
def register
#user = User.new(params[:user])
if #user.valid?
#user.save
session[:user_id] = #user.id
flash[:notice] = 'Welcome.'
redirect_to sign_in_url
else
render :action => "new_user"
end
end
This is my new_user form:
<p>Sign Up</p>
<%= form_for #user, :as => :user, :url => new_user_path, :method => :put do |f| %>
<p>
<%= f.label 'username:' %><br/>
<%= f.text_field :username %>
<%= show_field_error(#user, :username) %>
</p>
<p>
<%= f.label 'email:' %><br/>
<%= f.text_field :email %>
<%= show_field_error(#user, :email) %>
</p>
<p>
<%= f.label 'password:' %><br/>
<%= f.password_field :password %>
<%= show_field_error(#user, :password) %>
</p>
<p>
<%= f.label 'password confirmation:' %><br/>
<%= f.password_field :password_confirmation %>
<%= show_field_error(#user, :password_confirmation) %>
</p>
<p>
<%= f.submit 'Sign Up' %>
<%= f.submit 'Clear Form', :type => 'reset' %>
</p>
Can anybody point me in the right direction?
Your call to new_user_path in your form references the url to User#new if you have defined resources :users in your routes.rb file. You will need to replace new_user_path with register_user_path, if you have defined register in your routes file. Double check for the path with by running rake routes, though.
From what I can see, there is no need to use have the register action. It'd make more sense to use RESTful actions new, create, index, show, edit, update, and destroy in your case, since your logic follows the intuition behind them. Rails makes this convention easy to follow. See the routing Rails guide here for more.

Devise invitable show inviter name or email

I want to be able to show the user that sent out the invitation rather than just my domain when sending out a devise invitation but haven't been able to find any documentation on this.
The two places where I need to show this name are in the invitation email-
(in place of 'Someone')
<p>Hello <%= #resource.email %>!</p>
<p>Someone has invited you to <%= root_url %>, you can accept it through the link below.</p>
<p><%= link_to 'Accept invitation', accept_invitation_url(#resource, :invitation_token => #resource.invitation_token) %></p>
<p>If you don't want to accept the invitation, please ignore this email.<br />
Your account won't be created until you access the link above and set your password.</p>
and the set password page.
<h4>You're seeing this page because someone has invited you to the site</h4>
<%= simple_form_for resource, :as => resource_name, :url => invitation_path(resource_name), :html => { :method => :put } do |f| %>
<%= devise_error_messages! %>
<%= f.hidden_field :invitation_token %>
<div class="row">
<div class="signup_well span3 offset1">
<legend><%= t 'devise.invitations.edit.header' %></legend>
<%= f.input :password %>
<%= f.input :password_confirmation %>
<%= hidden_field_tag :token_key, resource.invitation_token %>
<%= f.submit t("devise.invitations.edit.submit_button") %>
<% end %>
</div>
I may over looking any documentation on the best approach to do this. Your help saves a lot of frustration. Thank you.
This should works: <%= #resource.invited_by.first_name %>.

ruby on rails form and passing its parameter to controller

When the view pass the parameters to controller,
controller gets nil for all of the arguements somehow.
Can anyone how to fix this?? Thanks!
and I have no model called "Message"
controllers/messages_controller.rb
def deliver
recipient = User.find_by_username(params[:recipient])
subject = params[:subject]
body = params[:body]
current_user.send_message(recipient, body, subject)
redirect_to :controller => 'messages', :action => 'received'
flash[:notice] = "message sent!"
end
views/messages/new.html.erb
<%=form_for :messages, url: url_for( :controller => :messages, :action => :deliver ) do |f| %>
<div class="field">
<%= f.label :subject %><br />
<%= f.text_field :subject %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_field :body %>
</div>
<div class="actions">
<%= f.submit %>
<% end %>
Check your source HTML to better understand what FormHelpers do.
With the form_for f.text_field will generate names attributes in the format:
messages[subject]
Consequently, your params will be in the format:
params[:messages][:subject]
You can also use <%= debug params %> to inspect what's in params, it's very helpful.
You can get parameter value using datas = params[:messages]
These values are in array form. So you can fetch array datas If you want to individual data then usesubject = datas[:subject]
body = datas[:body]
To check run following code in view
<%= subject %>
this gives the value of subject.

How can I use "Form_tag" as opposed to "Form_for" in this file

I am new to Ruby on Rails and have been helped immensely by Michael Hartl's excellent book: Ruby on Rails Tutorial. I have gotten to Chapter 8 and am now on the exercises in that chapter. I am having ( I assume a typical "newbie") problem with exercise 1. In this exercise it is asked "1.Refactor the signin form to use form_tag in place of form_for." I have tried to searching for assistance with this in Stackoverflow, Google, Railscast, and many other "web searches" for two days now and I do not seem to find the assistance that I need to answer this problem. The file I am trying to modify with form_tag is below:
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
I am using Rails 3.2.3 in this application. Can anybody point me in the correct direction? Can anyone help me with this problem? I would be most appreciative.
This is the implementation that uses form_tag:
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_tag( url: sessions_path ) do %>
<%= label_tag :email %>
<%= text_field_tag :email %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
I am using Rspec 2.9.0 and below are the failing tests:
describe "signin page" do
before { visit signin_path }
it { should have_selector('h1', text: 'Sign in') }
it { should have_selector('title', text: 'Sign in') }
end
and
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_selector('title', text: 'Sign in') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
end
end
and
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
Here's my routes file:
SampleApp::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
get "users/new"
root to: 'static_pages#home'
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
end
I have just completed this exercise as well, so I am by no means an expert; however, this is the code that has worked for me and passed all the tests:
../app/views/sessions/new.html.erb
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span 6 offset 3">
<%= form_tag sessions_path do %>
<%= label_tag :email %>
<%= text_field_tag :email, params[:email] %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New User?<%= link_to "Sign Up Now", signup_path %> </p>
</div>
</div>
I also needed to change the ../app/controllers/sessions_contoller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user] = user.id
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_path
end
end
Whilst this works, I'm not entirely sure why it does; if someone could explain why the changes in the controller are required it would be much appreciated. I know that this could be posed a s a separate question but it is closely related to OP and I'm sure we would both find it extremely useful in understanding not just how to get this to work but why it works this way. The following are the original view and controller files:
Original 'form_for' new.html.erb:
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
and the original sessions_controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email])
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
def destroy
sign_out
redirect_to root_path
end
end
I am working on the same step of the tutorial, and your question helped me finding my way.
The use of label and text_field, instead of label_tag and text_field_tag is working fine, and you don't have to change the controller code (this produce the same HTML code as with the original form_for method).
<%= form_tag(sessions_path) do %>
<%= label :session, :email %>
<%= text_field :session, :email %>
<%= label :session, :password %>
<%= password_field :session, :password %>
<%= submit_tag("Sign in", class: "btn btn-large btn-primary") %>
<% end %>
You can read details in http://guides.rubyonrails.org/form_helpers.html#dealing-with-model-objects
The RoR guides go over how form_tag works.
http://guides.rubyonrails.org/form_helpers.html
I got caught not naming the the fields right. When you view source of the original, it shows you the naming scheme.
<%= form_tag(sessions_path) do %>
<%= label_tag 'session_email', 'Email' %>
<%= text_field_tag 'session[email]' %>
<%= label_tag 'session_password', 'Password' %>
<%= password_field_tag 'session[password]' %>
<%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>
<% end -%>
You have a Session_Helper that you aren't using in your implementation.
EDIT your helper methods.
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
session[:user_id] = user.id
end
def sign_out
cookies.delete(:remember_token)
session[:user_id] = nil
end
Then you can simply use the appropriate methods in your session controller. This is a neater implementation that follows the modular approach to design. There also seems to be issues with rspec.
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
fill_in "Email", with: user.email.upcase
fill_in "Password", with: user.password
click_button "Sign in"
end
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
Even though everything is correct when you visit the page these tests are flagged. My guess is that you need to change before do because if it was doing what you want it to do the tests would pass.
Anyways, I'm curious to what the problem is with rspec if anyone has an idea!
I think that problem is with user.email.upcase. You don't need .upcase, when you remove it tests will pass.

rails 3 form_for undefined variable error

I got a undefined variable or method error when I try to render a partial view which is a form. The code like following:
in a partial view file, show.html.erb:
<ul class="users">
<% #users.each do |user| %>
<%= render 'pending' %>
<% end %>
</ul>
in _pending.html.erb:
<%= form_for current_user.friendships.build(:friendb_id => user.id) do |f| %>
<div><%= f.hidden_field :friendb_id %></div>
<div class="actions"><%= f.submit "Confirm" %></div>
<% end %>
The rspec error is:
undefined local variable or method `user'
I tried:
<%= render :partial => 'pending', :locals => {:user => user} %>
but it still doesn't work
Anyone knows why the form cannot find user variable?