More Ruby on Rails test issues - ruby-on-rails

I am on chapter 9 and it seems that the tests are failing once again. Here is the relevant code:
sessions_helper.rb:
module SessionsHelper
#logs in the given user
def log_in(user)
session[:user_id] = user.id
end
#Remember a user in a persistent session
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
def current_user?
user == current_user
end
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
#Forgets a persistent session
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
end
Here is users_edit_test.rb:
require 'test_helper'
class UsersEditTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
def setup
#user = users(:michael)
end
test "successful edit" do
log_in_as(#user)
get edit_user_path(#user)
assert_template 'users/edit'
name = "Foo Bar"
email = "foo#bar.com"
patch user_path(#user), user: { name: name,
email: email,
password: "",
password_confirmation: ""}
assert_not flash.empty?
assert_redirected_to #user
#user.reload
assert_equal name, #user.name
assert_equal email, #user.email
end
test "unsuccessful edit" do
log_in_as(#user)
get edit_user_path(#user)
assert_template 'users/edit'
patch user_path(#user), user: { name: "",
email: "foo#invalid",
password: "foo",
password_confirmation: "bar"}
assert_template 'users/edit'
end
end
Here is users_controller.rb:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
# debugger
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
#Handle a successful save
log_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
#Handle a successful update.
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
#Before filters
# Confirms a logged-in user
def logged_in_user
flash[:danger] = "Please login to access this page."
redirect_to login_url
end
def correct_user
#user - User.find(params[:id])
redirect_to(root_url) unless #user == current_user
end
end
And lastly here are the errors:
1) Failure:
UsersEditTest#test_unsuccessful_edit [/home/robert/sample_app/test/integration/users_edit_test.rb:32]:
expecting <"users/edit"> but rendering with <[]>
2) Failure:
UsersEditTest#test_successful_edit [/home/robert/sample_app/test/integration/users_edit_test.rb:15]:
expecting <"users/edit"> but rendering with <[]>
3) Failure:
UsersControllerTest#test_should_redirect_update_when_logged_in_as_wrong_user [/home/robert/sample_app/test/controllers/users_controller_test.rb:37]:
Failed assertion, no message given.
4) Failure:
UsersControllerTest#test_should_redirect_edit_when_logged_in_as_wrong_user [/home/robert/sample_app/test/controllers/users_controller_test.rb:30]:
Failed assertion, no message given.
This is annoying cause I don't see anything different from the book and the code that I have (in most parts copied and pasted from the book). In the book it apparently works, but when I run the test I get these four failures.

I see, you have a typo in your code.
In your users_controller.rb's correct_user method, you have: #user - User.find(params[:id]), which should be: #user = User.find(params[:id]).
Change that to:
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless #user == current_user
end
See if that fixes your issue.
If not, try adding these two methods to your SessionsHelper module.
If that also does not fix your issue. I would suggest you to clone the original working repo from github and try to figure out what you have missed in your version. I have cloned this github repo and all the tests are passing.

Related

Rails Tutorial Chapter 10 (friendly forwarding) test error, Expected response to be a <3XX: redirect>, but was a <200: OK>

Well, im new to coding with Rails and Michael Hartl tutorial is awesome, and till now i've benn able to find my coding errors... right now im in chapter 10 "Friendly Forwarding" and whilst performing the test for succesfull edit i stumbled on an error i cant see through.
test_successful_edit_with_friendly_forwarding#UserEditTest (1.07s)
Expected response to be a <3XX: redirect>, but was a <200: OK>
test/integration/user_edit_test.rb:32:in `block in '
my user_edit_test is:
require 'test_helper'
class UserEditTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
end
test "unsuccessful edit" do
log_in_as(#user)
get edit_user_path(#user)
assert_template 'users/edit'
patch user_path(#user), params: { user: { name: "",
email: "foo#invalid",
password: "foo",
password_confirmation: "bar" } }
assert_template 'users/edit'
end
test "successful edit with friendly forwarding" do
get edit_user_path(#user)
log_in_as(#user)
assert_redirected_to edit_user_url(#user)
name = "Foo Bar"
email = "foo#bar.com"
patch user_path(#user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
assert_not flash.empty?
assert_redirected_to #user <--- this is line 32 from the test
#user.reload
assert_equal name, #user.name
assert_equal email, #user.email
end
end
My users controller is:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params) # Not the final implementation!
if #user.save
log_in #user
flash[:success] = "Welcome to the Sample App"
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
# Handle a successful update.
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
#Before Filters
#Confirms a logged-in user
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
My sessions.Helper is:
module SessionsHelper
#logs in the given user
def log_in(user)
session[:user_id] = user.id
end
# Remembers a user in a persistent session.
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
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
#returns true if the current user is the given 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
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# Logs out current user
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
# Redirects to stored location (or to the default).
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
# Stores the URL trying to be accessed.
def store_location
session[:forwarding_url] = request.original_url if request.get?
end
end
And my Sessions Controller is:
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by(email: params[:session][:email].downcase)
if #user && #user.authenticate(params[:session][:password])
log_in #user
params[:session][:remember_me] == '1' ? remember(#user) : forget(#user)
redirect_back_or #user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_url
end
end
From what i've seen in other questions i understand the problem but can't seem to find a way to fix it, i feel is right there in my face but dont see it.
FWIW, your friendly forwarding is working correctly and is tested in the first 3 lines of your test case. The assert_redirected_to #user test corresponds to your UsersController#update, more specifically the redirect_to #user statement in the if branch. What happens if you log into the site and update a user's profile? Check the logs at that point too.

Ruby on rails tutorial chapter 12 random unrelated errors created

This is my first foray into app development, and I have been following Michael Hartl's tutorial pretty much verbatim. All went fine until towards the end of chapter 12, when my tests started failing. The strange thing is that the tests which fail seem to be unrelated to the changes I made in chapter 12.
There are three failures and one error, and they are also duplicated by the local server when manually checked in the browser. Basically the logged_in_user before action doesn't seem to work, but only with some of the model actions, not all. I've tried to trace it with the debugger and tried to revert back to pre-chapter 12 commits (which all definitely worked) but I'm having trouble with database migrations and stuff and only introducing more and more errors. Below is the error log, my users controller, application controller and sessions helper. I feel like the error must be in one of those.
Many many thanks in advance for your help!
FAIL["test_should_redirect_update_when_not_logged_in", UsersControllerTest, 2016-03-06 05:58:45 -0800]
test_should_redirect_update_when_not_logged_in#UsersControllerTest
(1457272725.92s)
Expected true to be nil or false
test/controllers/users_controller_test.rb:27:in `block in '
ERROR["test_should_redirect_destroy_when_not_logged_in", UsersControllerTest, 2016-03-06 05:58:45 -0800]
test_should_redirect_destroy_when_not_logged_in#UsersControllerTest
(1457272725.96s) NoMethodError: NoMethodError: undefined
method admin?' for nil:NilClass
app/controllers/users_controller.rb:77:inadmin_user'
test/controllers/users_controller_test.rb:47:in block (2 levels) in <class:UsersControllerTest>'
test/controllers/users_controller_test.rb:46:inblock in '
app/controllers/users_controller.rb:77:in admin_user'
test/controllers/users_controller_test.rb:47:inblock (2 levels) in '
test/controllers/users_controller_test.rb:46:in `block in '
FAIL["test_should_redirect_edit_when_not_logged_in", UsersControllerTest, 2016-03-06 05:58:46 -0800]
test_should_redirect_edit_when_not_logged_in#UsersControllerTest
(1457272726.03s)
Expected true to be nil or false
test/controllers/users_controller_test.rb:21:in `block in '
FAIL["test_successful_edit_with_friendly_forwarding", UsersEditTest, 2016-03-06 05:58:46 -0800]
test_successful_edit_with_friendly_forwarding#UsersEditTest
(1457272726.07s)
Expected response to be a redirect to <[removed link]/users/633107804/edit> but was a redirect to <[removed
link]/users/633107804>.
Expected "[removed link]users/633107804/edit" to be === "[removed link]/users/633107804".
test/integration/users_edit_test.rb:22:in `block in '
class UsersController < ApplicationController
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to_users_url
end
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
def new
#user = User.new
end
def index
#users = User.paginate(page: params[:page])
end
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def following
#title = "Following"
#user = User.find(params[:id])
#users = #user.following.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title = "Followers"
#user = User.find(params[:id])
#users = #user.followers.paginate(page: params[:page])
render 'show_follow'
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
And the application controller:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
include SessionsHelper
private
#confirms a logged in user. Now placed in the application controller so both teh user controller and microposts controller can use it
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
end
And the sessions helper:
module SessionsHelper
#logs in the given user
def log_in(user)
session[:user_id] = user.id
end
# returns the current logged-in user (if any)
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: session[:user_id])
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
#current_user = user
end
end
end
# returns true if the user is logged in, and false otherwise
def logged_in?
!current_user.nil?
end
#Saves a user id and remember token digest to cookies
def remember(user)
user.remember
#Code to save cookies with 20 year expiry ("permanent") and "signed" so it can't be accessed by third party
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
# runs the forget method and removes remember tokens from cookies
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# logs out the given user
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
def current_user?(user)
user == current_user
end
# Redirects to stored location after trying to edit while logged out and then logging in
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
# Stores the URL trying to be accessed
def store_location
session[:forwarding_url] = request.url if request.get?
end
end
Userscontrollertest:
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def setup
#user = users(:Joe)
#other_user = users(:Jane)
end
test "should redirect to index when not logged in" do
get :index
assert_redirected_to login_url
end
test "should get new" do
get :new
assert_response :success
end
test "should redirect edit when not logged in" do
get :edit, id: #user
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect update when not logged in" do
patch :update, id: #user, user: { name: #user.name, email: #user.email }
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect edit when logged in as wrong user" do
log_in_as(#other_user)
get :edit, id: #user
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect update when logged in as the wrong user" do
log_in_as(#other_user)
patch :update, id: #user, user: { name: #user.name, email: #user.email }
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
delete :destroy, id: #user
end
assert_redirected_to login_url
end
test "should redirect destroy when logged in as a non-admin" do
log_in_as(#other_user)
assert_no_difference 'User.count' do
delete :destroy, id: #user
end
assert_redirected_to root_url
end
end
After comparing your code to what I have in my tutorial code, try changing the order of the before_action statements in your UsersController and see if that works:
Before:
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
After:
before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
All the before_action statements are run in the order they are defined in the controller, so for the update action, you're currently running the correct_user filter first, which calls current_user?(#user), which calls current_user:
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: session[:user_id])
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
#current_user = user
end
end
end
At that point in your tests, since you haven't logged in a user yet, you don't have a session[:user_id], so that if statement fails, and you also don't have a cookies.signed[:user_id], so the elsif statement fails, leaving you with a nil return value and #current_user not being set.
At some point in your request in the test, you seem to be finding its way over to the admin_user method, which is calling current_user.admin?, and since at this point current_user is nil, you're getting the NoMethodError: undefined method admin?' for nil:NilClass that you're seeing.

Failure: UsersSignupTest#test_valid_signup_information_with_account_activation Expected: 1 Actual: 2

I am following railstutorial and am having this error in chapter 10.
I thought it should be similar with this post. Unfortunately, the solution does not work with my problem.
Changing 1 into 2 in line assert_equal 1, ActionMailer::Base.deliveries.size in user_signup_test.rb make the test GREEN. lol.
But I am a complete noob so do not really understand the real issue.
could someone show me where I miss?
Failure:
UsersSignupTest#test_valid_signup_information_with_account_activation
[/home/xxx/sample_app/test/integration/users_signup_test.rb:30]:
Expected: 1
Actual: 2
user_signup_test.rb
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
def setup
ActionMailer::Base.deliveries.clear
end
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, user: { name: "",
email: "user#invalid",
password: "foo",
password_confirmation: "bar" }
end
assert_template 'users/new'
end
test "valid signup information with account activation" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, user: { name: "Example User",
email: "user#example.com",
password: "password",
password_confirmation: "password" }
end
assert_equal 1, ActionMailer::Base.deliveries.size
user = assigns(:user)
assert_not user.activated?
# Try to log in before activation.
log_in_as(user)
assert_not is_logged_in?
# Invalid activation token
get edit_account_activation_path("invalid token")
assert_not is_logged_in?
# Valid token, wrong email
get edit_account_activation_path(user.activation_token, email: 'wrong')
assert_not is_logged_in?
# Valid activation token
get edit_account_activation_path(user.activation_token, email: user.email)
assert user.reload.activated?
follow_redirect!
assert_template 'users/show'
assert is_logged_in?
end
#assert_template 'users/show'
#assert is_logged_in?
end
user_controller.rb
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update, :index, :destroy ]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def new
#user = User.new
end
def index
##users = User.all
#users = User.paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
#debugger
end
def create
#user = User.new(user_params) # Not the final implementation!
if #user.save
# Handle a successful save.
#log_in #user
#flash[:success] = "Welcome to the Sample App!"
#redirect_to #user
#user.send_activation_email
UserMailer.account_activation(#user).deliver_now
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
#Handle a successful update
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
# Before filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
#redirect_to root_url unless #user == current_user
redirect_to root_url unless current_user?(#user)
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
user_mailer.rb
class UserMailer < ApplicationMailer
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.account_activation.subject
#
def account_activation(user)
#user = user
mail to: user.email, subject: "Account activation"
end
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.password_reset.subject
#
def password_reset
#greeting = "Hi"
mail to: "to#example.org"
end
end
application_mailer.rb
class ApplicationMailer < ActionMailer::Base
#default from: "from#example.com"
default from: "noreply#example.com"
layout 'mailer'
end
account_activation_controller.eb
class AccountActivationsController < ApplicationController
def edit
user = User.find_by(email: params[:email])
if user && !user.activated? && user.authenticated?(:activation, params[:id])
user.activate
log_in user
flash[:success] = "Account activated!"
redirect_to user
else
flash[:danger] = "Invalid activation link"
redirect_to root_url
end
end
end
session_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
if user.activated?
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
#redirect_to user
redirect_back_or(user)
else
message = "Account not activated."
message += "Check your email for the activation link."
flash[:warning] = message
redirect_to root_url
end
else
flash.now[:danger] = 'Invalid email/password combination' # Not quite right!
render 'new'
end
end
def destroy
log_out if logged_in?
log_out
redirect_to root_url
end
end
user_mailer_test.rb
require 'test_helper'
class UserMailerTest < ActionMailer::TestCase
test "account_activation" do
user = users(:michael)
user.activation_token = User.new_token
mail = UserMailer.account_activation(user)
assert_equal "Account activation", mail.subject
assert_equal [user.email], mail.to
assert_equal ["noreply#example.com"], mail.from
assert_match user.name, mail.body.encoded
assert_match user.activation_token, mail.body.encoded
assert_match CGI::escape(user.email), mail.body.encoded
end
test "password_reset" do
mail = UserMailer.password_reset
assert_equal "Password reset", mail.subject
assert_equal ["to#example.org"], mail.to
assert_equal ["noreply#example.com"], mail.from
assert_match "Hi", mail.body.encoded
end
end
#user.send_activation_email
UserMailer.account_activation(#user).deliver_now
Without seeing the rest of your code, this looks like it should send two separate emails. The second line definitely does send an email, but we can't see the User model to know what the first line is doing.
If that code does send two emails, then the test is failing correctly.

Michael Hartl’s Rails Tutorial chapter 9 (section 9.2.3 Friendly Forwarding) tests failed

I am new to programming and getting the following errors while trying to get through the 9th chapter of Rails Tutorial. I checked the code several times but still didn’t understand why my local variable or method isn’t being defined. Every time I rewrite the code I get similar errors: undefined local variable or method ‘current_user’.
Error:
ERROR["test_layout_links", SiteLayoutTest, 0.888518]
test_layout_links#SiteLayoutTest (0.89s)
ActionView::Template::Error: ActionView::Template::Error: undefined local variable or method `current_user' for #<#<Class:0x007fcd97c44cf0>:0x007fcd97c4c4a0>
app/helpers/sessions_helper.rb:22:in `logged_in?'
app/views/layouts/_header.html.erb:8:in `_app_views_layouts__header_html_erb__1982327839123609485_70260496954760'
app/views/layouts/application.html.erb:12:in `_app_views_layouts_application_html_erb___2753884707929057206_70260450931560'
test/integration/site_layout_test.rb:6:in `block in <class:SiteLayoutTest>'
app/helpers/sessions_helper.rb:22:in `logged_in?'
app/views/layouts/_header.html.erb:8:in `_app_views_layouts__header_html_erb__1982327839123609485_70260496954760'
app/views/layouts/application.html.erb:12:in `_app_views_layouts_application_html_erb___2753884707929057206_70260450931560'
test/integration/site_layout_test.rb:6:in `block in <class:SiteLayoutTest>'
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])
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
redirect_back_or user
else
flash.now[:danger] = 'Invalid email/password combination' #Not quite right!
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_url
end
end
users_controller
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
sessions_helper
module SessionsHelper
#logs in the given user.
def log_in(user)
session[:user_id] = user.id
end
#Remembers a user in a persistent session.
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
#Returns the user corresponding to the remember token cookie.
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
#Forgets a persistent session.
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
#logs out the current user.
def log_out
forget(current_user)
session.delete(:user_id)
#current_user = nil
end
# Redirects to stored location (or to the default).
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
# Stores the URL trying to be accessed.
def store_location
session[:forwarding_url] = request.url if request.get?
end
end
sessions_helper_test
require 'test_helper'
class SessionsHelperTest < ActionView::TestCase
def setup
#user = users(:michael)
remember(#user)
end
test "current_user returns right user when session is nil" do
assert_equal #user, current_user
assert is_logged_in?
end
test "current_user returns nil when remember digest is wrong" do
#user.update_attribute(:remember_digest, User.digest(User.new_token))
assert_nil current_user
end
end
I think you may be missing the current_user method. It's defined here.
Though the name is similar, current_user is a completely different method to current_user?. The question mark is a convention that typically means the method will return either true or false.
You're missing a current_user method in your sessions_helper.rb. Check back in Chapter 8.57

Hartl Rails Tutorial Section 9.2.2 cookie not created

I am working through the Hartl rails tutorial, within Chapter 9 I am trying to replicate the tests for restricting the edit action to the current user:
require 'spec_helper'
describe "Authentication" do
subject { page }
....
....
....
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong#example.com") }
before { sign_in user, no_capybara: true }
describe "submitting a GET request to the Users#edit action" do
before { get edit_user_path(wrong_user) }
specify { expect(response.body).not_to match(full_title('Edit user')) }
specify { expect(response).to redirect_to(root_url) }
end
describe "submitting a PATCH request to the Users#update action" do
before { patch user_path(wrong_user) }
specify { expect(response).to redirect_to(root_url) }
end
end
end
I have then implemented the code as described within the book, but the tests still fail:
Failures:
1) Authentication as wrong user submitting a PATCH request to the Users#update action
Failure/Error: specify { expect(response).to redirect_to(root_url) }
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/signin>.
Expected "http://www.example.com/" to be === "http://www.example.com/signin".
# ./spec/requests/authentication_pages_spec.rb:100:in `block (4 levels) in <top (required)>'
I have investigated by adding some logging to the sign_in method called within the test:
def sign_in(user, options={})
Rails.logger.debug "sign_in "+"*"*15
if options[:no_capybara]
# Sign in when not using Capybara.
remember_token = User.new_remember_token
cookies[:remember_token] = remember_token
Rails.logger.debug "Created cookie rt: "+ cookies[:remember_token].to_s
user.update_attribute(:remember_token, User.encrypt(remember_token))
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
Within the log the create cookie remember_token is reported as blank. If I change the sign in to sign_in user (without the no capybara option) I can see that the user is signed in and the cookie populated, but when I visit the edit action the cookie is no longer populated.
How can I investigate further as to why the cookie is being destroyed?
Thanks...
For information I've included the application code below:
content of users_controller.rb
class UsersController < ApplicationController
before_action :signed_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def new
#user = User.new
end
def show
#user = User.find(params[:id])
logger.debug "User show: "+ #user.to_yaml
logger.debug "cookie on user show: "+ cookies[:remember_token].to_yaml
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render 'new'
end
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
def edit
logger.debug "Edit user method"
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before filters
def signed_in_user
si = signed_in?
logger.debug "*"*200
logger.debug "signed in user: signed in?: "+si.to_s
redirect_to signin_url, notice: "Please sign in." unless si
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
end
Content of sessions_controller.rb
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
Content of sessions_helper.rb
module SessionsHelper
def sign_in(user)
logger.debug "Sessions Helper sign in Method"
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?
s_in = !current_user.nil?
logger.debug "signed_in?: "+s_in.to_s
s_in
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
def current_user=(user)
#current_user = user
end
def current_user
logger.debug "getting current user"
logger.debug "cookie: "+ cookies[:remember_token].to_s
remember_token = User.encrypt(cookies[:remember_token])
logger.debug "rt: "+ remember_token.to_yaml
logger.debug "current_user before: "+ #current_user.to_yaml
#current_user ||= User.find_by(remember_token: remember_token)
logger.debug "current_user after: "+ #current_user.to_yaml
#current_user
end
def current_user?
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user == current_user
end
end
There is nothing wrong with your authentication test
Its the code in users_controller.rb file
please remove the indicated(<---) line from your update method from users_controller.rb file.
It is clear from the error itself that it is expected to be at root_ulr but landing on sign_in_url.
This is happening because you have added one line "sign_in #user" to your users_controller.rb file in update method.so as per you code it is redirecting to "sign_in_url" which is unnecessary as the user have already logged in and updated his profile.I hope this will be helpful and resolve your issue.
update method in users_controller.rb file
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
sign_in #user `<----------- Remove this line
redirect_to #user
else
render 'edit'
end
end

Resources