I'm working on a project and I need to do a password reset system. I'm not using gem and I do not want to use it.
I found that the can_change filter runs and I'm redirected to the user page, which does not make sense to me, since the can_change filename is in the UsersController, not the PasswordResetsController
Email is sent without error. I click on the link and I go to /password_resets/edit?token=fewgfeggrf
, but when I click edit password, it does not work. How to solve?
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