Reputation: 6981
I've got a pretty standard User
model with Devise. Administrators are controlled with an :admin
boolean on the model, and users who aren't administrators cannot manage themselves (i.e., only administrators can make changes to users).
What I'd like is to permit users to reset their password if they forget it. They would enter their email address then be emailed a token which would grant them access to change it. I've started a solution but I really don't know how to proceed.
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
attr_accessor :current_password
attr_accessible :name, :password, :password_confirmation, :current_password, :email, :remember_me, :ftp, :colour1, :colour2, :logo, :logo2, :address, :url, :disclosure, :general_advice, :facebook, :twitter, :brand_id, :analytics
attr_protected :admin
validates_uniqueness_of :email, :ftp
belongs_to :brand
has_many :docs
has_many :orders, :through => :docs
has_attached_file :logo
has_attached_file :logo2
end
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new #guesting
if user.admin?
can :manage, :all
else
can :manage, :recoverable
end
end
end
And here's the method:
def reset
@idiot = User.where(:email => params[:email]).first
unless @idiot.nil?
Notifier.send_reset_notice(@idiot).deliver
@idiot.send_reset_password_instructions
redirect_to new_user_session_url
else
redirect_to new_user_session_url, :flash => { :error => "That email address matches no user." }
end
end
The user receives the Devise email but clicking on the link takes the user to the application root and not to a password reset form. I'm not sure how to proceed from here. Any thoughts? Cheers!
UPDATE
Relevant routes:
devise_for :users, :path => "d"
devise_scope :user do
get '/sign_in' => 'devise/sessions#new'
get '/sign_out' => 'devise/sessions#destroy'
end
Upvotes: 4
Views: 9737
Reputation: 8220
First, create controller for handle Devise::PasswordsController
class PasswordusersController < Devise::PasswordsController
prepend_before_filter :require_no_authentication
append_before_filter :assert_reset_token_passed, :only => :edit
def new
super
end
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
if successfully_sent?(resource)
redirect_to root_path, :notice => "Instruction has been send to your email"
else
respond_with(resource)
end
end
def edit
super
end
def update
self.resource = resource_class.reset_password_by_token(resource_params)
if resource.errors.empty?
resource.unlock_access! if unlockable?(resource)
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
set_flash_message(:notice, flash_message) if is_navigational_format?
sign_in(resource_name, resource)
redirect_to login_path, :notice => "Password has been change"
else
respond_with resource
end
end
protected
def after_sending_reset_password_instructions_path_for(resource_name)
root_path
end
def assert_reset_token_passed
super
end
def unlockable?(resource)
super
end
end
Than, run generate view for devise
copy new.html.erb
and edit.html.erb
from views/devise/passwords
to views/passwordusers
on routes.rb
you can config such as :
devise_scope :user do
get '/reset_password' => "passowrdusers#new", :as => :reset_password
get '/new_password' => "passwordusers#edit", :as => :new_password
end
edit link on devise/mailer/reset_password_instructions.html.erb
<p><%= link_to 'Change My Password', new_password_path(@resource, :reset_password_token => @resource.reset_password_token) %></p>
finally, on view form login add this
<%= link_to "Forgot Password?", reset_password_url(resource_name) %>
UPDATE
on routes.rb
you can config such as :
devise_scope :user do
get '/reset_password' => "passowrdusers#new", :as => :reset_password
get '/new_password' => "passwordusers#edit", :as => :new_password
post '/send_email' => 'passwordusers#create', :as => :create_password
put '/change' => 'passwordusers#update', :as => :update_password
end
on views/passwordusers/new.html.erb
<%= form_for("user", :url => create_password_path(resource_name), :html => { :method => :post }) do |f| %>
on views/passwordusers/edit.html.erb
<%= form_for("user", :url => update_password_path(resource_name), :html => { :method => :put }) do |f| %>
Upvotes: 4