Reputation: 1797
I have seen this particular error (or question/topic) in many other places. However, none of the solutions have solved my problem. Regarding the chapter 8 of Michael Hartl book, I have added the following integration test:
test "login with remembering" do
log_in_as(@user, remember_me: '1')
assert_not_nil cookies['remember_token']
assert_equal cookies['remember_token'], assigns(:user).remember_token
end
However, the last assert_equal
gives me the error I have put in the title.
What I have done so far:
Suggested by other questions, I have generated another migration adding remember_token
to the User
model. However, this did not solve the problem.
How can I solve this?
Upvotes: 1
Views: 1806
Reputation: 434
I had this same problem and was able to solve it thanks to Stefan Muntwyler's answer. What happened to me (and probably to the poster, as well) is that the exercise that required you to make the user variable into an instance variable (@user) was later overridden by some updated code that removed the instance variable you created.
To fix this, change this code in sessions_controller.rb:
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_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'
render 'new'
end
end
To this:
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_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'
render 'new'
end
end
Upvotes: 0
Reputation: 428
Check your sessions_controller. It should use an instance variable (@user) within the create method, anywhere you reference the user.
def create
@user = User.find_by(email: params[:session][:email].downcase)
.
.
.
end
Rails Tutorial - Chapter 9.26 Exercises 1)
Inside a test, you can access instance variables defined in the controller by using assigns with the corresponding symbol. For example, if the create action defines an @user variable, we can access it in the test using assigns(:user).
Changing the create method to use an instance variable was left as an exercise near Chapter 9.26. But the users_login_test "login with remembering" method relies on assigns(:user) to access the remember_token.
test "login with remembering" do
log_in_as(@user, remember_me: '1')
assert_equal assigns(:user).remember_token, cookies['remember_token']
assert_not_empty cookies['remember_token']
end
Upvotes: 1
Reputation: 310
Without seeing the full error message, it's hard to know exactly where the problem is, but when I ran into this one it was because I had forgotten to save my sessions_controller.rb before running the test.
Here is the exact error I received:
ERROR["test_login_with_remembering", UsersLoginTest, 2016-03-03 20:00:56 -0600]
test_login_with_remembering#UsersLoginTest (1457056856.16s)
NoMethodError: NoMethodError: undefined method `remember_token' for nil:NilClass
test/integration/users_login_test.rb:42:in `block in <class:UsersLoginTest>'
test/integration/users_login_test.rb:42:in `block in <class:UsersLoginTest>'
The following is my create method inside of the sessions controller:
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_to @user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
Upvotes: 1
Reputation: 7044
In your test the assigns(:user) instance does not exists. You are using the @user instance in log_in_as
method. Why are you not using it in your last assert_equal method ? Try this
assert_equal cookies['remember_token'], @user.remember_token
I think it will work.
And find out why you are using assigns(:user) and why it is nil.
Edited:
If it will not work then first try to reload the user data before you make the assertion:
@user.reload
assert_equal cookies['remember_token'], @user.remember_token
And I would add one more assertion to your test that checks if the user has 'remember_token' after he logged in. It will help you to detect the wrong place in your code. If this assertion will fail then you will make sure that there is something wrong in your authorization process.
test "login with remembering" do
log_in_as(@user, remember_me: '1')
@user.reload
assert_not_nil @user.remember_token
assert_not_nil cookies['remember_token']
assert_equal cookies['remember_token'], @user.remember_token
end
Upvotes: 0
Reputation: 176472
The problem there is probably not that the User
model has no remember_token
attribute, rather that the value of assigns(:user)
is nil, which means your controller doesn't properly set the @user
attribute.
Upvotes: 1