0

I am working on a project and I need to do a password reset system. I'm not using any gem.

mailers/password_reset.rb

class PasswordReset < ActionMailer::Base

default from: '[email protected]'

def send_password_reset(user)
    @user = user

    @reset_link = edit_password_resets_url({
        token: @user.password_reset_token
    })

    mail({
        :to => user.email, 
        :bcc => ['reset password <[email protected]'],
        :subject => I18n.t('password_reset.send_password_reset.subject')
    }) 
end

end

views/password_reset/send_password_reset.html.erb

<h2><%= t '.greetings', full_name: @user.full_name %></h2>
 <p><%= t '.body_html', link: link_to(t('.click_here'), @reset_link) %></p>

controllers/password_resets_controller.rb

class PasswordResetsController < ApplicationController
before_action :require_no_authentication, only: [:new, :create, :edit, :update]

def new

end

def create
    user = User.find_by(email: params[:email])

    if user.present?

        user.generate_password_reset

        PasswordReset.send_password_reset(user).deliver

        redirect_to root_url, notice: t('flash.notice.check_email_reset')
    else 
        flash[:alert] = t('flash.alert.cannot_find_email_reset')
        render :new
    end
end

def edit
    @user = User.find_by(password_reset_token: params[:token])
end

def update
    @user = User.find_by!(password_reset_token: params[:token])

    if @user.password_reset_sent_at < 2.hours.ago
        redirect_to new_password_reset_path, alert: t('flash.alert.time_expired')
    end

    if @user.update(password_reset_user_params)
        @user.password_reseted!
        redirect_to new_user_sessions_path, notice: t('flash.notice.password_reseted_complete')

    else
        render :edit
    end
end

private

def password_reset_user_params
    params.require(:user).permit(:password, :password_confirmation)
end

end

models/user.rb

class User < ActiveRecord::Base

VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
VALID_BIRTHDAY_REGEX = /[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4}/

validates_presence_of :full_name, :email, :birthday, :about

validates_length_of :about, minimum: 10, maximum: 100

validates_format_of :email, with: VALID_EMAIL_REGEX
validates_uniqueness_of :email
validates_format_of :birthday, with: VALID_BIRTHDAY_REGEX 

has_secure_password

scope :confirmed, -> { where.not(created_at: nil) }

before_create do |user|
    user.confirmation_token = SecureRandom.urlsafe_base64
end

def confirm!
    return if confirmed?

    self.confirmed_at = Time.current
    self.confirmation_token = ''

    save!
end 

def confirmed?
    confirmed_at.present?
end

def self.authenticate(email, password)
    user = confirmed.find_by(email: email)

    if user.present?
        user.authenticate(password)
    end
end

def generate_password_reset
    self.password_reset_token = SecureRandom.urlsafe_base64
    self.password_reset_sent_at = Time.zone.now
    save!
end

def password_reseted?
    password_reset_token.present?
end

def password_reseted!
    return if password_reseted?

    self.password_reset_token = ''
    self.password_reseted_at = Time.current

    save!
end


def password_reseted_expired?
    password_reset_sent_at < 1.hours.ago
end

end

views/password_resets/new.html.erb

<%= form_tag password_resets_path, :method => :post do %>
<div>
    <%= label_tag :email %>
    <%= text_field_tag :email, params[:email] %>
</div>
<div><%= submit_tag %></div>

views/password_resets/edit.html.erb

<%= form_for @user do |f| %>
<p>
    <%= f.label :password %><br>
    <%= f.password_field :password %>
    <%= error_field(@user, :password) %>
</p>

<p>
    <%= f.label :password_confirmation %><br>
    <%= f.password_field :password_confirmation %>
    <%= error_field(@user, :password_confirmation) %>
</p>

<p>
    <%= f.submit %>
</p>

controllers/users_controller.rb

class UsersController < ApplicationController

before_action :can_change, only: [:edit, :update]
before_action :require_no_authentication, only: [:new, :create]

def show
    @user = User.find(params[:id])
end

def new
    @user = User.new
end

def create
    @user = User.new(user_params)

    if @user.save
        Signup.confirm_email(@user).deliver

        redirect_to new_user_sessions_path, notice: t('flash.notice.user_created') 
    else
        render action: :new
    end
end

def edit
    @user = User.find(params[:id])
end

def update
    @user = User.find(params[:id])

    if @user.update(user_params)
        flash[:notice] = t('flash.notice.user_updated')
        redirect_to @user
    else
        render action: :edit
    end
end

private

def user_params
    params.require(:user).permit(:full_name, :email, :birthday, :password, :password_confirmation, :about)
end

def can_change
    unless user_signed_in? && current_user == user
        redirect_to user_path(params[:id])
    end
end

def user
    @user ||= User.find(params[:id])
end

end

config/routes

resource :password_resets

The email is sent with no errors. But when I click on "Edit Password" at /password_resets/edit?token=fewgfeggrf, I am redirected to user's perfil! How can I change that?

7
  • Check the logs, you will find where the request gets halted and the redirect is being fired, it will tell you the exact before_filter you need to check Commented Feb 3, 2015 at 1:07
  • There is no change at columns when I click on Edit Password button when I see the logs Commented Feb 3, 2015 at 1:12
  • the server log should show that the request triggers a redirect and where the execution halted, just do the request and check the console where the server is running and you must have a line something like "execution halted at :you_before_filter" at the end of the request Commented Feb 3, 2015 at 1:15
  • Well, I got that ` Started PATCH "/pt/users/1" for 127.0.0.1 at 2015-02-02 22:18:21 -0200 Processing by UsersController#update as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"AhQSH6mAiDdlqophAyDmfrQeN/9DVhuzV4xvh5i24FA=", "user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Att user", "locale"=>"pt", "id"=>"1"} Redirected to localhost:3000/users/1 Filter chain halted as :can_change rendered or redirected ´ Commented Feb 3, 2015 at 1:25
  • check the can_change filter, if you fix that filter you are done, maybe you need to get the user with the token BEFORE the can_change filter applies, or maybe just add a skip_before_filter :can_change if you don't need it Commented Feb 3, 2015 at 1:32

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.