I cannot get the test to pass for the password reset. It shows the following:
1) Error:
PasswordResetsTest#test_password_resets:
NoMethodError: undefined method `[]' for nil:NilClass
app/controllers/password_resets_controller.rb:10:in `create'
test/integration/password_resets_test.rb:14:in `block in <class:PasswordResetsTest>'
I am not sure what is causing the nil. Please help.
PasswordResetsController
class PasswordResetsController < ApplicationController
before_action :get_user, only: [:edit, :update]
before_action :valid_user, only: [:edit, :update]
before_action :check_expiration, only: [:edit, :update] # Case (1)
def new
end
def create
#user = User.find_by(email: params[:password_reset][:email].downcase)
if #user
#user.create_reset_digest
#user.send_password_reset_email
flash[:info] = "Email sent with password reset instructions"
redirect_to root_url
else
flash.now[:danger] = "Email address not found"
render 'new'
end
end
def edit
end
def update
if params[:user][:password].empty? # Case (3)
#user.errors.add(:password, "can't be empty")
render 'edit'
elsif #user.update_attributes(user_params) # Case (4)
log_in #user
flash[:success] = "Password has been reset."
redirect_to #user
else
render 'edit' # Case (2)
end
end
private
def user_params
params.require(:user).permit(:password, :password_confirmation)
end
# Before filters
def get_user
#user = User.find_by(email: params[:email])
end
# Confirms a valid user.
def valid_user
unless (#user && #user.activated? &&
#user.authenticated?(:reset, params[:id]))
redirect_to root_url
end
end
# Checks expiration of reset token.
def check_expiration
if #user.password_reset_expired?
flash[:danger] = "Password reset has expired."
redirect_to new_password_reset_url
end
end
end
PasswordsResetsTest
require 'test_helper'
class PasswordResetsTest < ActionDispatch::IntegrationTest
def setup
ActionMailer::Base.deliveries.clear
#user = users(:michael)
end
test "password resets" do
get new_password_reset_path
assert_template 'password_resets/new'
# Invalid email
post password_resets_path, params: { password_reset: { email: "" } }
assert_not flash.empty?
assert_template 'password_resets/new'
# Valid email
post password_resets_path,
params: { password_reset: { email: #user.email } }
assert_not_equal #user.reset_digest, #user.reload.reset_digest
assert_equal 1, ActionMailer::Base.deliveries.size
assert_not flash.empty?
assert_redirected_to root_url
# Password reset form
user = assigns(:user)
# Wrong email
get edit_password_reset_path(user.reset_token, email: "")
assert_redirected_to root_url
# Inactive user
user.toggle!(:activated)
get edit_password_reset_path(user.reset_token, email: user.email)
assert_redirected_to root_url
user.toggle!(:activated)
# Right email, wrong token
get edit_password_reset_path('wrong token', email: user.email)
assert_redirected_to root_url
# Right email, right token
get edit_password_reset_path(user.reset_token, email: user.email)
assert_template 'password_resets/edit'
assert_select "input[name=email][type=hidden][value=?]", user.email
# Invalid password & confirmation
patch password_reset_path(user.reset_token),
params: { email: user.email,
user: { password: "foobaz",
password_confirmation: "barquux" } }
assert_select 'div#error_explanation'
# Empty password
patch password_reset_path(user.reset_token),
params: { email: user.email,
user: { password: "",
password_confirmation: "" } }
assert_select 'div#error_explanation'
# Valid password & confirmation
patch password_reset_path(user.reset_token),
params: { email: user.email,
user: { password: "foobaz",
password_confirmation: "foobaz" } }
assert is_logged_in?
assert_not flash.empty?
assert_redirected_to user
end
end
Any help would be greatly appreciated.
i looked into Hartl's source and he has this line:
post password_resets_path, password_reset: { email: #user.email }
and yours is
post password_resets_path, params: { password_reset: { email: #user.email }}
this is new syntax that is compatible on Rails 5. the above solution is Rails 4.
You are missing #user.update_attribute(:reset_digest, nil) in your app/controllers/password_resets_controller.rb file. Update your file with below content.
class PasswordResetsController < ApplicationController
before_action :get_user, only: [:edit, :update]
before_action :valid_user, only: [:edit, :update]
before_action :check_expiration, only: [:edit, :update] # Case (1)
def new
end
def create
#user = User.find_by(email: params[:password_reset][:email].downcase)
if #user
#user.create_reset_digest
#user.send_password_reset_email
flash[:info] = "Email sent with password reset instructions"
redirect_to root_url
else
flash.now[:danger] = "Email address not found"
render 'new'
end
end
def edit
end
def update
if params[:user][:password].empty? # Case (3)
#user.errors.add(:password, "can't be empty")
render 'edit'
elsif #user.update_attributes(user_params) # Case (4)
log_in #user
#user.update_attribute(:reset_digest, nil)
flash[:success] = "Password has been reset."
redirect_to #user
else
render 'edit' # Case (2)
end
end
private
def user_params
params.require(:user).permit(:password, :password_confirmation)
end
# Before filters
def get_user
#user = User.find_by(email: params[:email])
end
# Confirms a valid user.
def valid_user
unless (#user && #user.activated? &&
#user.authenticated?(:reset, params[:id]))
redirect_to root_url
end
end
# Checks expiration of reset token.
def check_expiration
if #user.password_reset_expired?
flash[:danger] = "Password reset has expired."
redirect_to new_password_reset_url
end
end
end
Update as per suggested and you will be able to see green test.
Related
I'm plugging away after an extended leave (a year) on the Ruby on Rails Tutorial by Michael Hartl. I'm getting a user_param error in an integration test. I've gone to 4 sources trying to figure out where I'm going wrong on the strong parameters including the documentations.
Since starting up again last week, I have four hours generally getting to know the tutorial project and another twelve hours reading over chapters 7 to 12, then an hour chasing this problem. I keep feeling like I must be scanning too quickly over this stuff & keenly realizing I am not good at tracing errors.
Can anyone shed some light on what I'm missing? I'd also like any tips on trouble shooting this type of thing too! Thanks for your time!
Here's the error message I'm getting from console:
ERROR["test_password_resets", PasswordResetsTest, 2016-10-20 15:24:37 +0000]
test_password_resets#PasswordResetsTest (1476977077.03s)
NoMethodError: NoMethodError: undefined method `[]' for nil:NilClass
app/controllers/password_resets_controller.rb:10:in `create'
test/integration/password_resets_test.rb:14:in `block in <class:PasswordResetsTest>'
app/controllers/password_resets_controller.rb:10:in `create'
test/integration/password_resets_test.rb:14:in `block in <class:PasswordResetsTest>'
ERROR["test_invalid_signup_information", UsersSignupTest, 2016-10-20 15:24:37 +0000]
test_invalid_signup_information#UsersSignupTest (1476977077.04s)
ActionController::ParameterMissing: ActionController::ParameterMissing: param is missing or the value is empty: user
app/controllers/users_controller.rb:52:in `user_params'
app/controllers/users_controller.rb:25:in `create'
test/integration/user_signup_test.rb:12:in `block (2 levels) in <class:UsersSignupTest>'
test/integration/user_signup_test.rb:11:in `block in <class:UsersSignupTest>'
app/controllers/users_controller.rb:52:in `user_params'
app/controllers/users_controller.rb:25:in `create'
test/integration/user_signup_test.rb:12:in `block (2 levels) in <class:UsersSignupTest>'
test/integration/user_signup_test.rb:11:in `block in <class:UsersSignupTest>'
ERROR["test_valid_signup_information_with_account_activation", UsersSignupTest, 2016-10-20 15:24:37 +0000]
test_valid_signup_information_with_account_activation#UsersSignupTest (1476977077.05s)
ActionController::ParameterMissing: ActionController::ParameterMissing: param is missing or the value is empty: user
app/controllers/users_controller.rb:52:in `user_params'
app/controllers/users_controller.rb:25:in `create'
test/integration/user_signup_test.rb:25:in `block (2 levels) in <class:UsersSignupTest>'
test/integration/user_signup_test.rb:24:in `block in <class:UsersSignupTest>'
app/controllers/users_controller.rb:52:in `user_params'
app/controllers/users_controller.rb:25:in `create'
test/integration/user_signup_test.rb:25:in `block (2 levels) in <class:UsersSignupTest>'
test/integration/user_signup_test.rb:24:in `block in <class:UsersSignupTest>'
FAIL["test_should_get_edit", PasswordResetsControllerTest, 2016-10-20 15:24:37 +0000]
test_should_get_edit#PasswordResetsControllerTest (1476977077.05s)
Expected response to be a <success>, but was <302>
test/controllers/password_resets_controller_test.rb:11:in `block in <class:PasswordResetsControllerTest>'
Here's the controller in question (users_controller):
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
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(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
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
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
Here's the user_signup_test:
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
def setup
ActionMailer::Base.deliveries.clear
end
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user#invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.field_with_errors'
end
test "valid signup information with account activation" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { 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", email: user.email)
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
end
Here is the last controller - missed that one somehow ...
require 'test_helper'
class PasswordResetsTest < ActionDispatch::IntegrationTest
def setup
ActionMailer::Base.deliveries.clear
#user = users(:michael)
end
test "password resets" do
get new_password_reset_path
assert_template 'password_resets/new'
# Invalid email
post password_resets_path, password_reset: { email: "" }
assert_not flash.empty?
assert_template 'password_resets/new'
# Valid email
post password_resets_path,
password_reset: { email: #user.email }
assert_not_equal #user.reset_digest, #user.reload.reset_digest
assert_equal 1, ActionMailer::Base.deliveries.size
assert_not flash.empty?
assert_redirected_to root_url
# Password reset form
user = assigns(:user)
# Wrong email
get edit_password_reset_path(user.reset_token, email: "")
assert_redirected_to root_url
# Inactive user
user.toggle!(:activated)
get edit_password_reset_path(user.reset_token, email: user.email)
assert_redirected_to root_url
user.toggle!(:activated)
# Right email, wrong token
get edit_password_reset_path('wrong token', email: user.email)
assert_redirected_to root_url
# Right email, right token
get edit_password_reset_path(user.reset_token, email: user.email)
assert_template 'password_resets/edit'
assert_select "input[name=email][type=hidden][value=?]", user.email
# Invalid password & confirmation
patch password_reset_path(user.reset_token),
email: user.email,
user: { password: "foobaz",
password_confirmation: "barquux" }
assert_select 'div#error_explanation'
# Empty password
patch password_reset_path(user.reset_token),
email: user.email,
user: { password: "",
password_confirmation: "" }
assert_select 'div#error_explanation'
# Valid password & confirmation
patch password_reset_path(user.reset_token),
email: user.email,
user: { password: "foobaz",
password_confirmation: "foobaz" }
assert is_logged_in?
assert_not flash.empty?
assert_redirected_to user
end
end
PasswordResetController:
class PasswordResetsController < ApplicationController
before_action :get_user, only: [:edit, :update]
before_action :valid_user, only: [:edit, :update]
before_action :check_expiration, only: [:edit, :update] # Case (1)
def new
end
def create
#user = User.find_by(email: params[:password_reset][:email].downcase)
if #user
#user.create_reset_digest
#user.send_password_reset_email
flash[:info] = "Email sent with password reset instructions"
redirect_to root_url
else
flash.now[:danger] = "Email address not found"
render 'new'
end
end
def edit
end
def update
if params[:user][:password].empty? # Case (3)
#user.errors.add(:password, "can't be empty")
render 'edit'
elsif #user.update_attributes(user_params) # Case (4)
log_in #user
flash[:success] = "Password has been reset."
redirect_to #user
else
render 'edit' # Case (2)
end
end
private
def user_params
params.require(:user).permit(:password, :password_confirmation)
end
# Before filters
def get_user
#user = User.find_by(email: params[:email])
end
# Confirms a valid user.
def valid_user
unless (#user && #user.activated? &&
#user.authenticated?(:reset, params[:id]))
redirect_to root_url
end
end
# Checks expiration of reset token.
def check_expiration
if #user.password_reset_expired?
flash[:danger] = "Password reset has expired."
redirect_to new_password_reset_url
end
end
end
I think you should remove params key before user parameters, e.g.:
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'
assert_select 'div#error_explanation'
assert_select 'div.field_with_errors'
end
Also you can debug received parameters in controller with pry:
add gem pry to your Gemfile (if there is no one);
run $ bundle install;
add binding.pry in controller before method user_params is called;
check that params contains expected parameters.
The following test that I have written is:
test "valid signup information with account activation" do
get root_path
assert_difference 'User.count', 1 do
post_via_redirect users_path, user: { user_name: "Example1234",
email: "user1234#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("invalidtoken", email: user.email)
assert_not is_logged_in?
#Valid token, wrong email
get edit_account_activation_path(user.activation_token, email: "wrongemail")
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 'recipes/index'
assert is_logged_in?
end
And I get the following error:
ERROR["test_valid_signup_information_with_account_activation", UsersSignupTest, 1.4278587700100616]
test_valid_signup_information_with_account_activation#UsersSignupTest (1.43s)
NoMethodError: NoMethodError: undefined method `activated?' for nil:NilClass
test/integration/users_signup_test.rb:30:in `block in <class:UsersSignupTest>'
Note that line 30 is the first assert_not user.activated?
It appears that the assigns(:user) is not getting the actual user and I can't seem to figure out why.
I'm following Hartl's tutorial and this is the test in Chapter 10 . Any ideas why the user is not returning
EDIT:
Here is my controller code:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
.....
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
#user.send_activation_email
format.html { redirect_to root_url notice: 'Please check your email to activate.' }
format.json { head :no_content }
else
format.html { render 'new' }
format.json { render json: #user.errors }
end
end
end
...
end
Here is my Account Activations Controller.
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! Welcome!."
redirect_to recipes_url
else
flash[:danger] = "Invalid activation link."
redirect_to root_url
end
end
end
OK! So I figured this one out eventually.
I'm still not sure why but I changed the code in the test from: post_via_redirect to just a post and it worked properly.
I did this mostly because I noticed in the documentation for assigns(:) that it comes after a post rather than a post_via_redirect.
I believe your error is not in your user controller, but in your account_activation controller:
class AccountActivationsController < ApplicationController
def edit
user = User.find_by(email: params[:email])
if user && !user.activated? && user.authenticated?(:activation,params[:id])
user.activate....
Update Error may be in the test
From the tutorial
test "valid signup information with account activation" do
get signup_path #You have get root_path here!!!
assert_difference 'User.count', 1 do
post users_path, user: { name: "Example User",
email: "user#example.com",
password: "password",
password_confirmation: "password" }
end
The signup_path is where the methods are that contain user.activated?
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.
I've been working through M.Hartl's Ruby on Rails tutorial for a while now, and I've been able to work out when I've made typos that caused my integration tests to fail and the like, but I've run into one that I can't figure out. My get edit_password_reset_path() with correct arguments is redirecting to the home url, not password_resets/edit like it should.
The failing test:
FAIL["test_password_resets", PasswordResetsTest, 2015-11-02 15:50:02 +0000]
test_password_resets#PasswordResetsTest (1446479402.08s)
expecting <"password_resets/edit"> but rendering with <[]>
test/integration/password_resets_test.rb:37:in `block in <class:PasswordResetsTest>'
Here is my password_resets_test.rb:
require 'test_helper'
class PasswordResetsTest < ActionDispatch::IntegrationTest
def setup
ActionMailer::Base.deliveries.clear
#user = users(:michael)
end
test "password resets" do
get new_password_reset_path
assert_template 'password_resets/new'
# Invalid email
post password_resets_path, password_reset: { email: "" }
assert_not flash.empty?
assert_template 'password_resets/new'
# Valid email
post password_resets_path, password_reset: { email: #user.email }
assert_not_equal #user.reset_digest, #user.reload.reset_digest
assert_equal 1, ActionMailer::Base.deliveries.size
assert_not flash.empty?
assert_redirected_to root_url
# Password reset form
user = assigns(:user)
# Wrong email
get edit_password_reset_path(user.reset_token, email: "")
assert_redirected_to root_url
# Inactive user
user.toggle!(:activated)
get edit_password_reset_path(user.reset_token, email: user.email)
assert_redirected_to root_url
user.toggle!(:activated)
# Right email, wrong token
get edit_password_reset_path('wrong token', email: user.email)
assert_redirected_to root_url
# Right email, right token
get edit_password_reset_path(user.reset_token, email: user.email)
assert_template 'password_resets/edit' # This is the assertion that fails
assert_select "input[name=email][type=hidden][value=?]", user.email
# Invalid password & confirmation
patch password_reset_path(user.reset_token),
email: user.email,
user: { password: "foobazzz",
password_confirmation: "barquuxz" }
assert_select 'div#error_explanation'
# Empty password
patch password_reset_path(user.reset_token),
email: user.email,
user: { password: "",
password_confirmation: "" }
assert_not flash.empty?
# Valid password & confirmation
patch password_reset_path(user.reset_token),
email: user.email,
user: { password: "foobazzz",
password_confirmation: "foobazzz" }
assert is_logged_in?
assert_not flash.empty?
assert_redirected_to user
end
end
Here is my password_resets_controller.rb
class PasswordResetsController < ApplicationController
before_action :get_user, only: [:edit, :update]
before_action :valid_user, only: [:edit, :update]
before_action :check_expiration, only: [:edit, :update]
def new
end
def create
#user = User.find_by(email: params[:password_reset][:email].downcase)
if #user
#user.create_reset_digest
#user.send_password_reset_email
flash[:info] = "Email sent with password reset instructions"
redirect_to root_url
else
flash.now[:danger] = "Email address not found"
render 'new'
end
end
def edit
end
def update
if params[:user][:password].empty?
#user.errors.add(:password, "can't be empty")
render 'edit'
elsif #user.update_attributes(user_params)
log_in #user
flash[:success] = "Password has been reset"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:password, :password_confirmation)
end
def get_user
#user = User.find_by(email: params[:email])
end
def valid_user
unless (#user && #user.activated? &&
#user.authenticated?(:reset, params[:id]))
redirect_to root_url
end
end
def check_expiration
if #user.password_reset_expired?
flash[:danger] = "Password reset has expired."
redirect_to new_password_reset_url
end
end
end
The authenticated? method in user.rb :
# Returns true if the given token matches the digest.
def authenticated?(attribute, token)
digest = send("#{attribute}_digest")
return false if digest.nil?
BCrypt::Password.new(digest).is_password?(token)
end
I'm not super sure what else is needed to figure out my problem. I've searched StackOverflow, worked through the code a second time, and I've even compared the source code at M.Hartl's github repo.
Link to the appropriate branch on my repo.
I'm trying to follow exactly this part of the tutorial.
The problem was in the user.rb model.
In my model, I had the following code:
def create_reset_digest
self.reset_token = User.new_token
update_attribute(:reset_digest, User.digest(reset_digest))
update_attribute(:reset_sent_at, Time.zone.now)
end
Note the second parameter to the first update_attribute() call, reset_digest. That should actually be reset_token. The correct method looks like this:
def create_reset_digest
self.reset_token = User.new_token
update_attribute(:reset_digest, User.digest(reset_token))
update_attribute(:reset_sent_at, Time.zone.now)
end
I'm new to rails and I'm stuck in chapter 9.2.2 "Requiring the Right User", when I add the 2nd user archer to the users.yml file and add the other code to the user_controller_test.rb and the users_controller.rb, the run bundle exec rake test, I get 30 errors stating that:
ERROR["test_layout_links", SiteLayoutTest, 0.019046]
test_layout_links#SiteLayoutTest (0.02s)
ActiveRecord::StatementInvalid: ActiveRecord::StatementInvalid: SQLite3::SQLException: table users has no column named archer: INSERT INTO "users" ("name", "email", "password_digest", "archer", "created_at", "updated_at", "id") VALUES ('Michael Example', 'michael#example.com', '$2a$04$kDHpg7Zah2wc3X.YbWs5E.pytz8byEkUYo6O7uyPCftblGq3BEogW', '---
name: Sterling Archer
email: duchess#example.gov
password_digest:
users.yml code
michael:
name: Michael Example
email: michael#example.com
password_digest: <%= User.digest('password') %>
archer:
name: Sterling Archer
email: duchess#example.gov
password_digest: <%= User.digest('password') %>
users_controller_test.rb code
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def setup
#user = users(:michael)
#other_user = users(:archer)
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 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
end
user_controller.rb code
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 Application of the Great Bakerboi!"
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)
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?
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
end
end
The problem is that you have inadvertently indented the definition of :archer in users.yml.