Reputation: 2080
Short: I have a devise model User I'm adding an option for User to be able to change their password in their profile page without needing to go via "Forgot password" option. Anyhow as this required an additional form with fields: :old_password, :new_password and :new_password_confirmation
that are not originally in model i had to create new seperate validations for them,
The form:
<%= form_for(@user, :url => {:controller => :members, :action => :editpass}, :html => {:method => :post}) do |f| %>
<input name="authenticity_token" type="hidden" value="<%= form_authenticity_token %>">
<table class="tables no-border">
<tr>
<%= f.label :old_password, "Old password" %>
</tr>
<tr>
<%= f.password_field :old_password, :autofocus => :true %>
</tr>
<tr>
<%= f.label :new_password, "New password" %>
</tr>
<tr>
<%= f.password_field :new_password %>
</tr>
<tr>
<%= f.label :new_password_confirmation, "Repeat new password" %>
</tr>
<tr>
<%= f.password_field :new_password_confirmation %>
</tr>
<tr>
<input type="submit" value="Change" class="btn" />
</tr>
</table>
</form>
<%= @user.errors.full_messages %>
<% end %>
The controller:
class MembersController < ApplicationController
before_filter :authenticate_user!
skip_before_filter :check_for_main
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
def editpass
current_user.change_password(params[:old_password], params[:new_password])
redirect_to member_path(current_user.id)
end
# User access restriction
def ban
end
def unban
end
end
The model: LOOK AT: Validation for fields :old_password / :new_password..
class User < ActiveRecord::Base
# Virtual attributes
# _password attributes serve in-profile password change and are not part of the model
attr_accessor :login, :apiid, :vcode, :old_password, :new_password, :new_password_confirmation
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]
# Registration show/edit form validation
validates :username, :presence => true,
:length => { :minimum => 6, :maximum => 255 },
:uniqueness => true
validates :apiid, :presence => true,
:numericality => { :only_integer => true },
:acc_api => true,
:on => :create
validates :vcode, :presence => true,
:length => { :minimum => 20, :maximum => 255 },
:on => :create
# In profile password
validates :old_password, :presence => true,
:length => { :minimum => 8, :maximum => 255 },
:if => :password_changed?
validates :new_password, :presence => true,
:length => { :minimum => 8, :maximum => 255 },
:if => :password_changed?,
:confirmation => true
validates :new_password_confirmation,
:presence => true
attr_accessible :login, :username, :group, :apiid, :vcode, :email, :password, :password_confirmation, :remember_me
# Register character belonging to user
after_create :register_characters
# Model association
has_many :apis
has_many :characters
# Allows user to reset password in profile
# for Forgot Password look at Devise
def change_password(oldpass, newpass)
if self.valid_password?(oldpass)
# User is logged out automatically by devise upon
# password change
self.password = newpass
self.save
else
return false
end
end
# Register account characters
def register_characters
require 'nokogiri'
require 'open-uri'
# Fetch account level xml
uri = "https://api.eveonline.com/account/Characters.xml.aspx?keyID=#{self.apiid}&vCode=#{self.vcode}"
xml = Nokogiri::XML(open(uri))
row = xml.xpath("//row")
# Create characters bound to user
row.each do |entry|
# Register new character
character = Character.new(
:charid => entry['characterID'].to_i,
:user_id => self.id,
:name => entry['name'],
:corp => entry['corporationName']
)
character.save
# Register character associated api credentials
api = Api.new(
:user_id => self.id,
:character_id => character.id,
:apiid => self.apiid,
:vcode => self.vcode
)
api.save
character.update_character
end
end
# Check if user is banned before login
def active_for_authentication?
super && self.banned == false
end
# Redefine authentication procedure to allow login with username or email
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login).downcase
where(conditions).where("username = '#{login}' OR email = '#{login}'").first
else
where(conditions).first
end
end
end
Upvotes: 1
Views: 686
Reputation: 2273
Basically, your password validations aren't being reached.
With the change_password
method, you're just passing in values from the controller to that method and using them to set password
. The model does not see old_password
and new_password
being set, so it cannot validate them. Also, since you're not passing in password_confirmation
and just setting password directly in the model (self.password = newpass
), password_confirmation
is not being used either.
As mentioned in another answer, you're better off using update_attributes
or whatever is recommended in the Devise docs. Hopefully my explanation adds some insight into why your method is not working.
If you want to stick to your change_password
method, you have to pass values to the attributes so they'll be validated by the model. Try something like this:
#controller
@user = current_user
if @user.change_password(params[:old_password], params[:new_password], params[:new_password_confirmation])
redirect_to member_path(current_user.id)
else
@errors = @user.errors.full_messages
render 'edit_password_view' # not sure what this action is named
# you now have an array of errors (@errors) that you can render however you see fit in the view
end
#model
def change_password(oldpass, newpass, newpass_conf)
self.password = newpass
self.old_password = oldpass
self.new_password = newpass
self.new_password_confirmation = newpass_conf
return self.save
end
Upvotes: 1
Reputation: 7674
I think the right way is to update user attributes instead of using change password. Maybe this guide can be of help:
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password
Upvotes: 0