Rspec Test Failure due to missing link - ruby-on-rails

Failures:
1) AuthenticationPages signin with invalid information followed by signout
Failure/Error: before { click_link "Sign out" }
Capybara::ElementNotFound:
no link with title, id or text 'Sign out' found
# (eval):2:in click_link'
# ./spec/requests/authentication_pages_spec.rb:28:inblock (5 levels) in '
This is a failure from my rspec test although I kind of know what is wrong but I dont know why its wrong.
My Rspec test:
describe "signin" do
before { visit signin_path }
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
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
Sessions Helper:
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def signed_in?
!current_user.nil?
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
_header.html.erb:
<header class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<%= link_to "TechnoEdge", root_path, id: "logo" %>
<nav>
<ul class="nav pull-right">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
<li><%= link_to "Users", '#' %></li>
<li id="fat-menu" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Account <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings",'#' %></li>
<li class="divider"></li>
<li>
<%= link_to "Sign out", signout_path, method: "delete" %>
</li>
</ul>
</li>
<% else %>
<li><%= link_to "Sign in", signin_path %></li>
<% end %>
</ul>
</nav>
</div>
</div>
</header>
Based on the embedded ruby code, the header should show sign in when there is no session created. However, I cant seem to be able to get it to work and I suspect that the problem lies within the sessions helper but I cant figure out what is wrong though.
Thanks in advance!
git source: https://github.com/tgxworld/sample_app

Related

Rails test fails for asserting the presence of a link, even though it actually works on the browser

I'm following Hartl's rails tutorial (Chapter 10) and am writing a test to validate that all the layout links are present. This is the test file:-
require 'test_helper'
class SiteLayoutTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
end
test "layout links" do
get root_path
assert_template 'static_pages/home'
assert_select "a[href=?]", root_path, count: 2
assert_select "a[href=?]", blog_path
assert_select "a[href=?]", about_path
assert_select "a[href=?]", help_path
assert_select "a[href=?]", contact_path
assert_select "a[href=?]", login_path
assert_select "a[href=?]", logout_path, count: 0
assert_select "a[href=?]", users_path, count: 0
log_in_as(#user)
assert is_logged_in?
assert_select "a[href=?]", users_path
assert_select "a[href=?]", logout_path
assert_select "a[href=?]", login_path, count: 0
end
end
Here, the test shows the following failure:-
FAIL["test_layout_links", SiteLayoutTest, 0.7809554979976383]
test_layout_links#SiteLayoutTest (0.78s)
Expected at least 1 element matching "a[href="/users"]", found 0..
Expected 0 to be >= 1.
test/integration/site_layout_test.rb:23:in `block in <class:SiteLayoutTest>'
If I comment out the assert_select "a[href=?]", users_path, it shows failure for the logout_path:-
FAIL["test_layout_links", SiteLayoutTest, 0.6692811190005159]
test_layout_links#SiteLayoutTest (0.67s)
Expected at least 1 element matching "a[href="/logout"]", found 0..
Expected 0 to be >= 1.
test/integration/site_layout_test.rb:24:in `block in <class:SiteLayoutTest>'
This is the header partial that contains the links for users_path and logout_path:-
<header class="navbar navbar-fixed-top navbar-inverse">
<div class="container">
<%= link_to "Sample app", root_path, id: "logo" %>
<nav>
<ul class="nav navbar-nav navbar-right">
<li><%= link_to "Home", root_path %></li>
<% if logged_in? %>
<li><%= link_to "Users", users_path %></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Account <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", edit_user_path(current_user) %></li>
<li class="divider"></li>
<li>
<%= link_to "Log out", logout_path, method: :delete %>
</li>
</ul>
</li>
<% else %>
<li><%= link_to "Log in", login_path %></li>
<% end %>
<li><%= link_to "Blog", blog_path %></li>
</ul>
</nav>
</div>
</header>
But as you can see in this screenshot, the Users and logout button do exist and they do work as intended.
I'm trying to figure out why the test fails even though the actual function in the application works. Help would be appreciated.
Update:-
The definitions for the is_logged_in? and log_in_as method:-
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/reporters"
Minitest::Reporters.use!
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Returns true if a test user is logged in.
def is_logged_in?
!session[:user_id].nil?
end
# Log in as a particular user.
def log_in_as(user)
session[:user_id] = user.id
end
end
class ActionDispatch::IntegrationTest
# Log in as a particular user.
def log_in_as(user, password: 'password', remember_me: '1')
post login_path, params: { session: { email: user.email,
password: password,
remember_me: remember_me }}
end
end
The definition for logged_in? :-
module SessionsHelper
# Logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
def current_user?(user)
user == current_user
end
# Returns the user corresponding to the remember token cookie.
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
def logged_in?
!current_user.nil?
end
The log_in_as sets you up with the session variable but it does not refresh the view so you still have the original display out there.
You should do
assert is_logged_in?
get root_path # <- refresh the view
assert_select "a[href=?]", users_path

error during signin in authentication_pages_spec

Fllowing the Michael hartl tutorial i'm getting the following error "undefined method pages" in authentication_pages_spec during sign in Chapter 8.
authentication_pages_spec.rb
require 'rails_helper'
RSpec.describe "AuthenticationPages", type: :request do
subject { pages }
describe "signin pages" do
before { visit signin_path }
it { should have_selector('h1', text: 'Sign in')}
it { should have_selector('title', text: 'Sign in')}
end
describe "signin" do
before { visit signin_path }
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
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)}
end
end
end
new.html.erb
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class = "row">
<div class = "col-md-6 col-md-offset-3">
<%= 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" %>
<p> New user? <%= link_to "Sign up now", signup_path %></p>
<% end %>
</div>
</div>
routes.rb
Rails.application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
root to: 'static_pages#home'
get '/signup', to: 'users#new'
get '/signin', to: 'sessions#new'
get '/signout', to: 'sessions#destroy', via: :delete
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
resources :users
end
Session_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email])
if user && user.authennticate(params[:session][:password])
#Sign the user in a redirect to the user's show page.
else
#Create an error message and re-render the signin form
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
end
end
It looks like you're using an old version of the tutorial (the current version uses MiniTest instead of RSpec), so you should probably consider switching over.
As for your errors, you would seem to have two spelling mistakes:
Change pages to page (singular), as that is the object that Capybara makes assertions against
Change user.authennticate to user.authenticate
For future questions, please copy and paste any error output in text format and refrain from posting screenshots.

Missing Template for signout

Finally after about two hours of messing with this thing, I have figured out most of my 7 errors. That said, I have a new one, and I have no clue how to get rid of it. I seem to be having the same issue I did with a similar question I asked, and that was before I started over with my most recent git commit. Needless to say, I am not amused right now. Anyway, here's the failure:
1) Authentication signin with valid information followed by signout
Failure/Error: before { click_link "Sign out" }
ActionView::MissingTemplate:
Missing template sessions/destroy, application/destroy with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee]}. Searched in:
* "/Users/Brawain/rails_projects/sample_app/app/views"
# ./spec/requests/authentication_pages_spec.rb:45:in `block (5 levels) in <top (required)>'
I actually don't know what code is necessary, so I'll post all my sessions stuff and the spec that's giving me trouble.
authentication spec
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "signin page" do
before { visit signin_path }
it { should have_content('Sign in') }
it { should have_title('Sign in') }
end
describe "signin" do
before { visit signin_path }
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_title('Sign in') }
it { should have_selector('div.alert.alert-error') }
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
end
end
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
visit '/signin'
fill_in "Email", with: user.email.upcase
fill_in "Password", with: user.password
click_button "Sign in"
end
it { should have_title(user.first) }
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
end
end
sessions helper
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def destroy
sign_out
redirect_to root_url
end
def sign_out
current_user.update_attribute(:remember_token,
User.encrypt(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end
end
sessions controller
class SessionsController < ApplicationController
def new
end
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
def destroy
end
end
sessions/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>
This isn't the whole page, but this is my body html code. I've included it because it has the pertinent links.
<div id="announcements">
TESTER TIME!
<% if signed_in? %>
<li><%= link_to "Users", '#' %></li>
<li id="fat-menu" class="dropdown">
Account <b class="caret"></b>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", '#' %></li>
<li class="divider"></li>
<li><%= link_to "Sign out", signout_path, method: "delete" %></li>
</ul>
</li>
<% else %>
<li><%= link_to "Sign in", signin_path %></li>
<% end %>
</div>
You need to destroy session in destroy function and then if you don't want to dislay any logout screen then redirect_to root_path
Mostly people redirect after logout
You must implement destroy method in SessionsController, not in SessionsHelper. Just move this method ( "destroy") from SessionsHelper to SessionsController. It should be like this:
sessions_controller.rb
class SessionsController < ApplicationController
...
def destroy
sign_out
redirect_to root_url
end
end
sessions_helper.rb
module SessionsHelper
...
def sign_out
current_user.update_attribute(:remember_token,
User.encrypt(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end

Rspec errors following Hartl's rails guide

I have been following the guide for a while now and unfortunately have been stuck getting these tests to pass. Thank you for your time because I have given up looking for what is wrong and am desperate for any help.
Failures:
1) signup with valid information after saving user
Failure/Error: it {should have_link('Sign out')}
expected link "Sign out" to return something
# ./spec/requests/user_pages_spec.rb:97:in `block (4 levels) in <top (required)>'
2) signup with valid information after saving user
Failure/Error: it { should have_selector('div.alert.alert-success', text: 'Welcome') }
expected css "div.alert.alert-success" with text "Welcome" to return something
# ./spec/requests/user_pages_spec.rb:96:in `block (4 levels) in <top (required)>'
3) signup with valid information after saving user
Failure/Error: it { should have_selector('title', text: user.name) }
expected css "title" with text "Example User" to return something
# ./spec/requests/user_pages_spec.rb:95:in `block (4 levels) in <top (required)>'
4) create user page
Failure/Error: it {should have_selector('h1', text: 'Creating New User')}
expected css "h1" with text "Creating New User" to return something
# ./spec/requests/user_pages_spec.rb:56:in `block (2 levels) in <top (required)>'
5) create user page
Failure/Error: it {should have_selector('title', text: 'Sign Up')}
expected css "title" with text "Sign Up" to return something
# ./spec/requests/user_pages_spec.rb:57:in `block (2 levels) in <top (required)>'
6) edit with valid information
Failure/Error: it { should have_selector('div.alert.alert-success') }
expected css "div.alert.alert-success" to return something
# ./spec/requests/user_pages_spec.rb:132:in `block (3 levels) in <top (required)>'
7) edit with valid information
Failure/Error: it { should have_selector('title', text: new_name) }
expected css "title" with text "New Name" to return something
# ./spec/requests/user_pages_spec.rb:131:in `block (3 levels) in <top (required)>'
8) edit with valid information
Failure/Error: it { should have_link('Sign out', href: signout_path) }
expected link "Sign out" to return something
# ./spec/requests/user_pages_spec.rb:133:in `block (3 levels) in <top (required)>'
9) edit with invalid info
Failure/Error: it {should have_content('error')}
expected there to be content "error" in "with invalid info"
# ./spec/requests/user_pages_spec.rb:117:in `block (3 levels) in <top (required)>'
10) edit page
Failure/Error: it { should have_selector('h1', text: "Update your profile") }
expected css "h1" with text "Update your profile" to return something
# ./spec/requests/user_pages_spec.rb:111:in `block (3 levels) in <top (required)>'
11) edit page
Failure/Error: it { should have_selector('title', text: "Edit user") }
expected css "title" with text "Edit user" to return something
# ./spec/requests/user_pages_spec.rb:112:in `block (3 levels) in <top (required)>'
12) profile page
Failure/Error: it{should have_selector('h2', text: user.name)}
expected css "h2" with text "Person 66" to return something
# ./spec/requests/user_pages_spec.rb:63:in `block (2 levels) in <top (required)>'
13) profile page
Failure/Error: it{should have_selector('title', text: user.name)}
expected css "title" with text "Person 67" to return something
# ./spec/requests/user_pages_spec.rb:64:in `block (2 levels) in <top (required)>'
My User Pages Spec
require 'spec_helper'
describe "UserPages" do
subject {page}
describe "index" do
before do
sign_in FactoryGirl.create(:user)
FactoryGirl.create(:user, name: "Bob", email: "bob#example.com")
FactoryGirl.create(:user, name: "Ben", email: "ben#example.com")
visit users_path
end
it { should have_selector('title', text: 'All users') }
it { should have_selector('h1', text: 'All Users') }
describe "pagination" do
before(:all) {30.times {FactoryGirl.create(:user)}}
after(:all) {User.delete_all}
it {should have_selector('div.pagination')}
describe "delete links" do
it { should_not have_link('delete') }
describe "as an admin user" do
let(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
visit users_path
end
it { should have_link('delete', href: user_path(User.first)) }
it "should be able to delete another user" do
expect { click_link('delete') }.to change(User, :count).by(-1)
end
it { should_not have_link('delete', href: user_path(admin)) }
end
end
end
it "should list each user" do
User.all.each do |user|
page.should have_selector('li', text: user.name)
end
end
end
end
describe "create user page" do
before {visit new_user_path}
it {should have_selector('h1', text: 'Creating New User')}
it {should have_selector('title', text: 'Sign Up')}
end
describe "profile page" do
let(:user){FactoryGirl.create(:user)}
before {visit user_path(user)}
it{should have_selector('h2', text: user.name)}
it{should have_selector('title', text: user.name)}
end
describe "signup" do
before { visit new_user_path }
let(:submit) { "Create my account" }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
end
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
choose("user_admin_true")
fill_in "Confirmation", with: "foobar"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving user" do
before {click_button submit}
let(:user) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out')}
end
end
end
describe "edit" do
let(:user) {FactoryGirl.create(:user)}
before do
sign_in user
visit edit_user_path(user)
end
describe "page" do
it { should have_selector('h1', text: "Update your profile") }
it { should have_selector('title', text: "Edit user") }
end
describe "with invalid info" do
before {click_button "Save changes"}
it {should have_content('error')}
end
describe "with valid information" do
let(:new_name) { "New Name" }
let(:new_email) { "new#example.com" }
before do
fill_in "Name", with: new_name
fill_in "Email", with: new_email
fill_in "Password", with: user.password
fill_in "Confirm Password", with: user.password
click_button "Save changes"
end
it { should have_selector('title', text: new_name) }
it { should have_selector('div.alert.alert-success') }
it { should have_link('Sign out', href: signout_path) }
specify { user.reload.name.should == new_name }
specify { user.reload.email.should == new_email }
end
end
Users Controller
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update, :destroy]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
def index
#users = User.paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Account creation succesful. Welcome to the CeFam Online Database"
redirect_to #user
else
render 'new'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User removed."
redirect_to users_url
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
def signed_in_user
flash[:notice] = "Please sign in." unless signed_in?
redirect_to signin_url unless signed_in?
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
end
Header
<header class="navbar navbar-fixed-top navbar-inverse">
<div class="navbar-inner">
<div class="container">
<%= link_to "Image Home Logo", '#', id: "logo" %>
<nav>
<ul class="nav pull-right">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<!--Visibile only when signed in-->
<% if signed_in? %>
<li><%= link_to "List users", users_path %></li>
<li><%= link_to "Search", '#' %></li>
<li><%= link_to "Add Entry", '#' %></li>
<li id="fat-menu" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Account <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", edit_user_path(current_user) %></li>
<li class="divider"></li>
<li><%= link_to "Sign out", signout_path, method: "delete" %>
</li>
<%else%>
<li><%= link_to "Sign in", signin_path %></li>
<%end%>
</ul>
</nav>
</div>
</div>
</header>
User's show.html.erb
<% provide(:title,#user.name) %>
<h1> User Profile </h1>
<h2><%=#user.name%><br>
<%= #user.email %><br>
Administrator: <%= #user.admin%>
</h2>
User's new.html.erb
<% provide(:title,'Sign Up')%>
<h1>Creating New User</h1>
<div class="row">
<div class="span4 offset4">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :admin %>
<%= f.radio_button :admin, "true"%> Yes <br>
<%= f.radio_button :admin, "false"%> No<br><br>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<br>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
Here's the source of at least one of your problems, look at your user_pages_spec.rb:
it "should list each user" do
User.all.each do |user|
page.should have_selector('li', text: user.name)
end
end
You want to test for User.paginate not User.all (because Capybara has no way of seeing past the default 30 rendered on a single paginated view). It's explained in the tutorial that testing for one page should suffice since the will_paginate gem is pretty well-tested already.
So replace that block with this, and your pagination tests should pass:
it 'should list each user' do
User.paginate(page: 1).each do |user|
page.should have_selector('li', text: user.name)
end
end

Hartl Rails Tutorial Chapter 8 - Cannot logout of Sample_App. All rspec tests pass

I would be extremely thankful for any help identifying why I cannot log out of my sample app.
* All of my rspec tests pass.
* When I go to log out on my localserver click log out, I am not logged out, and the link does not change to Sign In (although a rspec test for this passes).
Here are the relevant tests from authentication_pages_spec.rb
require 'spec_helper'
describe "AuthenticationPages" do
subject { page }
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
describe "signin" do
before { visit signin_path }
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-error') }
end
end
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
end
end
Here is sessions_controller.rb
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
Here is sessions_helper.rb
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def signed_in?
!self.current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
Here is _header.html.erb
<header class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<%= link_to "sample app", root_path, id: "logo" %>
<nav>
<ul class="nav pull-right">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
<li><%= link_to "Users", '#' %></li>
<li id="fat-menu" class="dropdown">
<a href='#' class="dropdown-toggle" data-toggle="dropdown">
Account <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", user_path(current_user) %></li>
<li><%= link_to "Settings", '#' %></li>
<li class="divider"></li>
<li>
<%= link_to "Sign out", signout_path, method: "delete" %>
</li>
</ul>
</li>
<% else %>
<li><%= link_to "Sign in", signin_path %></li>
<% end %>
</ul>
</nav>
</div>
</div>
</header>
And finally, here is the model user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = user.email.downcase }
before_save :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Here is what my WEBrick server is saying:
Started DELETE "/signout" for 127.0.0.1 at 2012-06-19 10:58:53 -0400
Processing by SessionsController#destroy as HTML
Parameters: {"authenticity_token"=>"qP1xAF4YXTaFmjeHxS5SgvUx+6+c6us5AL4jqgEBeqQ="}
Redirected to http://localhost:3000/
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2012-06-19 10:58:53 -0400
Processing by StaticPagesController#home as HTML
Rendered static_pages/home.html.erb within layouts/application (0.6ms)
Rendered layouts/_shim.html.erb (0.1ms)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" IS NULL LIMIT 1
Rendered layouts/_header.html.erb (3.1ms)
Rendered layouts/_footer.html.erb (0.5ms)
Completed 200 OK in 22ms (Views: 21.2ms | ActiveRecord: 0.3ms)
[2012-06-19 10:58:53] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
Started GET "/assets/application.css?body=1" for 127.0.0.1 at 2012-06-19 10:58:53 -0400
Served asset /application.css - 304 Not Modified (11ms)
[2012-06-19 10:58:53] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
In case it is some issue with the cookies here is what is happening when I check the cookies in the browser:
Checking the cookies:
1. I clear all cookies
2. go to localhost:3000. I am still signed in as user 2. I check cookies and I have no remember_token for local host. i do have a cookie named "_sample_app_session"
3. click sign out. Nothing happens, still signed in.
4. enter /signin. log in as user 3
5. i now have a remember_token in cookies.
6. click sign out. still showing i am signed in the top nav.
7. I click profile to see that I am logged in as user 2 (via debug)
8. i check cookies and remember token is gone, i still have the _sample_app_session
Do you have any way I can test what might be causing this? I am really trying to solve this so I can procede with the tutorial.
Oh I too was having the same problem. Even I was pulling my hair off for the same. Then one of my friend noticed the code and helped me out.
The problem is that you just missed to add the remember token from RAILS CONSOLE. Just check the part above cucumber which is optional. You will notice the part to add tokens from rails console.
rails console
User.first.remember_token
=> nil
User.all.each { |user| user.save(validate: false) }
User.first.remember_token
Make sure to migrate the db after pushing to heroku. I had a similar problem and it was gone after I run:
$ heroku run rake db:migrate

Resources