0

I'm working through the Ruby on Rails Tutorial and I'm most of the way through chapter 9. For some reason I keep getting these three errors, I checked with the github to see what if I was missing anything, but I have exactly what I should have. Here are my errors:

    1) Authentication signin with valid information followed by signout
     Failure/Error: before { click_link "Sign out" }
     NameError:
       undefined local variable or method `sign_out' for #<SessionsController:0x104c0b9d0>
     # ./app/controllers/sessions_controller.rb:19:in `destroy'
     # (eval):2:in `send'
     # (eval):2:in `click_link'
     # ./spec/requests/authentication_pages_spec.rb:44

  2) Authentication authorization for non-signed-in users when attempting to visit a protected page after signing in should render the desired protected page
     Failure/Error: page.should have_selector('title', :text => 'Edit user')
       expected css "title" with text "Edit user" to return something
     # ./spec/requests/authentication_pages_spec.rb:65

  3) Authentication authorization for non-signed-in users when attempting to visit a protected page after signing in when signing in again should render the default (profile) page
     Failure/Error: click_link "Sign out"
     NameError:
       undefined local variable or method `sign_out' for #<SessionsController:0x104c358c0>
     # ./app/controllers/sessions_controller.rb:19:in `destroy'
     # (eval):2:in `send'
     # (eval):2:in `click_link'
     # ./spec/requests/authentication_pages_spec.rb:70

My authentication_pages_spec.rb file:

 require 'spec_helper'

describe "Authentication" do

  subject { page }

  describe "signin page" do

    before { visit signin_path }

    it { should have_selector('h1',    :text => 'Sign in') }
    it { should have_selector('h1','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('h1', 'title', :text => 'Sign in') }
      it { should have_error_message }

      describe "after visiting another page" do
        before { click_link "Home" }
        it { should_not have_error_message }
      end
    end

    describe "with valid information" do
      let(:user) { FactoryGirl.create(:user) }
      before { sign_in user }

      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 have_link('Settings', :href => edit_user_path(user)) }
      it { should have_link('Users',    :href => users_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

  describe "authorization" do

    describe "for non-signed-in users" do
      let(:user) { FactoryGirl.create(:user) }

      describe "when attempting to visit a protected page" do
        before do
          visit edit_user_path(user)
          fill_in "Email",    :with => user.email
          fill_in "Password", :with => user.password
          click_button "Sign in"
        end

        describe "after signing in" do
          it "should render the desired protected page" do
            page.should have_selector('title', :text => 'Edit user')
          end

          describe "when signing in again" do
            before do
              click_link "Sign out"
              click_link "Sign in"
              fill_in "Email",    :with => user.email
              fill_in "Password", :with => user.password
              click_button "Sign in"              
            end

            it "should render the default (profile) page" do
              page.should have_selector('title', :text => user.name)
            end
          end
        end
      end

      describe "in the Users controller" do

        describe "visiting the edit page" do
          before { visit edit_user_path(user) }
          it { should have_selector('title', :text => 'Sign in') }
          it { should have_selector('div.alert.alert-notice') }
        end

        describe "submitting to the update action" do
          before { put user_path(user) }
          specify { response.should redirect_to(signin_path) }
        end

        describe "visiting the user index" do
          before { visit users_path }
          it { should have_selector('title', :text => 'Sign in') }
        end
      end

     describe "as wrong user" do
      let(:user) { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, :email => "wrong@example.com") }
      before { sign_in user }

      describe "visiting Users#edit page" do
        before { visit edit_user_path(wrong_user) }
        it { should_not have_selector('h1', 'title', :text => full_title('Edit user')) }
      end

      describe "submitting a PUT request to the Users#update action" do
        before { put user_path(wrong_user) }
        specify { response.should redirect_to(root_url) }
      end
    end
  end
end
end

My sessions_controller.rb file:

 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_back_or user
    else
      flash.now[:error] = 'Invalid email/password combination'
      render 'new'
    end
  end

  def destroy
    sign_out
    redirect_to root_path
  end
end

Any help is greatly appreciated! Thank you in advance!

Bhetzie
  • 2,852
  • 10
  • 32
  • 43

2 Answers2

0

You're invoking sign_out in a SessionsController instance, but there is no such method defined. Check the code in your "Sign out" view and check your routes.rb file to make sure that whatever link you're choosing is mapped properly. Usually, "sign out" is mapped to the destroy method.

Peter Alfvin
  • 28,599
  • 8
  • 68
  • 106
  • In my routes.rb file I have match '/signout', :to => 'sessions#destroy', :via => :delete I've been following the tutorial and I think these are the only 3 times that "sign out" is defined – Bhetzie Aug 13 '13 at 19:44
  • What about your view code - whatever is invoked by the `click_link "Sign out"`? – Peter Alfvin Aug 13 '13 at 19:47
  • Would you share the output of `rake routes` also? – Peter Alfvin Aug 13 '13 at 19:48
  • Yeah, never mind. `sign_out` is invoked by the `Sessions#destroy` defined in Figure 8.29 and as the other answer indicated, is proposed to be defined in a helper file as shown in Figure 8.30 – Peter Alfvin Aug 13 '13 at 19:52
0

Your error is because there is no sign_out method defined in your SessionsController or in the parent ApplicationController it inherits from.

According to the Rails tutorial in chapter 8 he has you define this method in the SessionsHelper, which is then mixed in to the ApplicationController. I think mixing helpers into controllers is not good (helpers should be restricted to views; others agree), but that's the way the tutorial is laid out for you.

Community
  • 1
  • 1
Abe Voelker
  • 30,124
  • 14
  • 81
  • 98
  • ohhhh! I think I must have quit without saving and my sessionsHelper didn't get saved. Thank you for finding that mistake! I appreciate the hyperlink too – Bhetzie Aug 13 '13 at 19:49