update_attributes clears password

I have a database table that contains encrypted passwords along with other information relating to users. When I do an update_attributes operation on a row in the table with a hash that does not contain a password, the password gets reset to the empty string. How can I stop this?

Remove the password key/value pair from the params hash before the update-attributes call if the password value is blank.

The hash does not contain a password key/value pair. In spite of this, the password is set to the empty string.

Parameters: {“utf8”=>“✓”, “authenticity_token”=>“AdPOoGvw9LXnkLEen9NzXo/yhwESO6hRxnICD2eK4Rk=”, “user”=>{“role_id”=>“3”}, “commit”=>“Update User”, “id”=>“1”}

> > I have a database table that contains encrypted passwords along with > other information relating to users. When I do an update_attributes > operation on a row in the table with a hash that does not contain a > password, the password gets reset to the empty string. How can I stop this?

Remove the password key/value pair from the params hash before the update-attributes call if the password value is blank.

The hash does not contain a password key/value pair. In spite of this, the password is set to the empty string.

  Parameters: {"utf8"=>"✓", "authenticity_token"=>"AdPOoGvw9LXnkLEen9NzXo/yhwESO6hRxnICD2eK4Rk=", "user"=>{"role_id"=>"3"}, "commit"=>"Update User", "id"=>"1"}

Have you got any callbacks in the model (before_save for example)? What does the log (log/development.log) show for the action? It should show the sql.

If you still can't see it post the action code, the model (strip out any irrelevant methods) and the log (just for the action).

Colin

Colin

What filters run in the model? What observers are operating? It would be worth setting a breakpoint at your update_attribute line and following through from there to see what happens to your password attribute.

I understand the problem now, but I do not see the solution. The model has a before_save filter that is causing the password to be reset. How do I stop this on an update?

require ‘authenticators/sql_encrypted’

class User < ActiveRecord::Base

belongs_to :role belongs_to :person

include CASServer::Authenticators::SQLEncrypted::EncryptedPassword

attr_accessor :password

validates :password, :confirmation => true, :length => { :within => 7…20 }, :format => { :with => /^.(?=.{7,20})(?=.[a-zA-Z])(?=.[0-9])(?=.[`~!@#$%^&-_=+|;':",./<>?]).$/ }, :presence => true, :if => :password_required?

validates_uniqueness_of :username

before_save :encrypt_password

protected

def password_required? encrypted_password.blank? || password.present? end

def encrypt_password self.encrypted_password = encrypt(self.password) end

end

The same way I said before - only run it if the password has been populated:

   def encrypt_password      self.encrypted_password = encrypt(self.password) unless self.password.blank?    end

But you will probably need to add same validation to ensure there is an encrypted_password - otherwise it would be possible to create accounts with blank passwords...

Thank you.

Also note that before_save (and pretty much all the callbacks) take :if and :unless parameters, like so

before_save do_something, :if => Proc.new {|model| model.some_boolean_attr_or_method }