Sam
Sam

Reputation: 33

Twilio SMS Forgotten Password Rails

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

Answers (1)

Tom Aranda
Tom Aranda

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

Related Questions