Reputation: 33
When a user clicks on "Forgot My Password" on the login screen, they are redirected to a route '/password-reset'. Right now, I'm trying to understand how to right the form for entering your email to receive and SMS from Twilio with a code.
<div class="form-group", style="width:50%;">
<%= form_for @user, url: password_patch_path(current_user) do |f| %>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: "form-control" %>
</div>
<%= f.submit "Get Confirmation Code", class: "btn btn-default" %>
<% end %>
</div>
The issue I'm running into is that @user is nil, and I'm uncertain if the url is correct at the beginning of the form for. It makes sense to me that @user is nil because no one is logged in, so I'm not sure what that should be.
My routes are
get '/password-reset', :to => 'passwords#edit', as: :password_reset
post '/password-reset', :to => 'passwords#reset', as: :password_edit
patch '/password-confirmation', :to => 'passwords#update', as: :password_patch
and my passwords controller looks like
class PasswordsController < ApplicationController
before_action :authenticated?, only: [:edit, :update]
def reset
ConfirmationSender.send_confirmation_to(current_user)
redirect_to new_confirmation_path
end
def edit
@user = current_user
end
def update
if passwords_not_empty? && passwords_equal?
current_user.update(password_params)
redirect_to users_dashboard_path(current_user.username), success: "Password Updated"
session[:authenticated] = false
else
redirect_to password_edit_path(current_user.username), warning: "Error, please try again."
end
end
private
def password_params
params.require(:user).permit(:password, :password_confirmation)
end
def passwords_not_empty?
params[:user][:password].length > 0 && params[:user][:password_confirmation].length > 0
end
def passwords_equal?
params[:user][:password] == params[:user][:password_confirmation]
end
def authenticated?
render :file => "#{Rails.root}/public/404.html", :status => 404 unless session[:authenticated]
end
end
Upvotes: 1
Views: 270
Reputation: 6036
You are right that there will be no current_user
if a user forgot his/her password. I would redesign as follows:
PasswordsContoller
class PasswordsController < ApplicationController
before_action :authenticated?, only: [:update]
def reset
@user = User.find_by(email: params[:user][:email])
if @user.present?
ConfirmationSender.send_confirmation_to(@user)
redirect_to new_confirmation_path
else
redirect_to password_reset_path, warning: "Email not found."
end
end
def edit
@user = User.new
end
...
end
Form
<div class="form-group", style="width:50%;">
<%= form_for @user, url: password_edit_path do |f| %>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: "form-control" %>
</div>
<%= f.submit "Get Confirmation Code", class: "btn btn-default" %>
<% end %>
</div>
The new edit
method seeds the form with a blank user. The new reset
method looks up the user by email and sends the token if the user is found. If not, it displays an email not found flash message and redirects back to the forgotten password form.
This also makes the form use the correct path for requesting a password confirmation.
Upvotes: 1