Set attr_accessor of active record (indirectly)

I have an attr_accessor for :password set on my user model.

If I have a variable "key" whose value is "password" and another variable "value" whose value is "secret", can I use this to set the :password? I can make it work several ways with regular model attributes, but not with attr_accessor attributes, e.g.

u.login

=> "mylogin"

u.write_attribute('login', 'mylogin2')

=> "mylogin2"

u.login

=> "mylogin2"

u.password

=> "foo"

u.write_attribute('password', 'mypass2')

=> "mypass2"

u.password

=> "foo"

Thanks --

Tom

tharrison wrote:

I have an attr_accessor for :password set on my user model.

If I have a variable "key" whose value is "password" and another variable "value" whose value is "secret", can I use this to set the :password? I can make it work several ways with regular model attributes, but not with attr_accessor attributes, e.g.

Tom

Tom, it sounds like you are using acts_as_authenticated or some variant of it.. in which case you probably have attr_accessible() somewhere in your user model. The reason the password field behaves differently than the others is because of it's omission from that list.

I strongly suggest you keep it out of that list but that is another topic altogether..

hth

ilan

Tom, this problem could use some better explaining.

Hi --

I have an attr_accessor for :password set on my user model.

If I have a variable "key" whose value is "password" and another variable "value" whose value is "secret", can I use this to set the :password? I can make it work several ways with regular model attributes, but not with attr_accessor attributes, e.g.

u.login

=> "mylogin"

u.write_attribute('login', 'mylogin2')

=> "mylogin2"

u.login

=> "mylogin2"

u.password

=> "foo"

u.write_attribute('password', 'mypass2')

=> "mypass2"

u.password

=> "foo"

You could do this:

   u.send("#{key}=", value)

attr_accessor :password just creates two methods for you:

   def password      @password    end

   def password=(password)      @password = password    end

so you have to proceed from there.

David

key = "password"     value = "secret"

    u.send("#{key}=", value)

Setting an attribute in Ruby is just sending a message.

HTH,   Stefan

Ok. Let me try.

I have a form for the User model. Most of the fields (attributes) are database columns, like first_name, login, etc. Password, however, is a virtual attribute, defined as an "attr_accessor". A person enters values into the form, including password, and when the form is submitted I have a hash of params[:user] containing attributes of the user. This form does not contain *all* of the values for the user model, and because in some cases the user model is new while in others it is an existing record, I wish to selectively set attribute. I have used various forms of write_attribute to accomplish this. All database-backed model attributes work fine (as in the case of "login" in the example). The plain-text password however is not stored in the model, so is defined as a virtual attribute (attr_accessor) on the model.

I can write values to the regular attributes of the model. I cannot successfully write values to the password field. While I get no error, the value is not updated in the model. Please see the example I provided.

If I have the name of an attribute, like "password", and a value (perhaps a computed one), how can I set this value on the @user instance variable?

Is that explained better?

Tom

Ok, firstly have you checked out the restful_authentication plugin? If not, you can make your life a lot easier by using it, and, if you can't use it, it will definitely help you to make your own login system work better.

In my login system based on restful_authentication i've got password and password_confirmation as attr_accessors. You should be able to send the #new or update_attribtes method the :password and :password_confirmation keys and it will update them in the model

It sounds like you haven't got any point where your model assigns your password to a column in the db (where it can be saved)

I've got a before_save hook which calls 'encrypt_password' method. This generates a hashed password and salt and assigns these to the database columns for storing my password (in my case hashed_password)

You can see all this in action by starting a new rails project, adding restful_authentication plugin and generating the models

Hope that helps a bit, though it doesn't answer directly why you can't update using update_attribute (seems a bit overcomplex) .BTW if you need to bypass parts of the validation code when you're just updating models, you can add :if => :method_name to the end of your validation commands which will check the output of a method for boolean result so you can selectively disable validation where necessary in certain parts of your app.

Thanks everyone. The "send" magic worked, which in turn helped me realized that rails has the "attributes" method (which uses send), and also honors other model settings. So, to update a potentially existing instance with only values that change:

# Find a, existing user if an optional parameter is passed, otherwise create a new one @user = User.find_by_some_optional_parameter(params[:optional_param])

User.new

# This will only update the attributes in from the user hash and not overwrite other aspects of the @user instance @user.attributes = params[:user]

Sometimes the hardest part of finding a solution is knowing the proper question to ask :slight_smile:

Tom