How to update a Protected Attributes

Hello All,

I am trying to update a protected attribute called 'picture'. I am
forced (I think) to use the following technique.

#first find a record or object
@user = User.find(:some_id_here)
..
..
# then assign the new value to protected attribute like this
@user.picture ="somenewpicture.jpg"

#and then update the object like this...
@user.update_attributes(other_updated_attributes_hash)

But instead I would like the following technique to update the object
and save to db.

@user = User.update(15, {:user_name => 'Samuel', :group =>
'expert', :picture="somenewpicture.jpg"})

The above technique does not update the picture attribute in db
because its protected attribute.

Is it possible to update the protected attributes using Class.update
method??

Is it not inefficient to find first unnecessarily, the object (record)
as in the first technique and then save back to db. This can be slower
in case of large database, where we have to unnecessarily find a
record even though we know the record which we want to update, and
thus making unnecessary query to find a record.

Is there any efficient method to do this along with updating protected
attributes?

Both techniques are analogous in that sense, they first find(id) and then call update_attributes on the model object. Protected attributes are protected in any kind of mass-assignment, that's the point of being protected.

To bypass that safety and be able to work without a model object use update_all or grab the connection.

-- fxn

Thanks for this hint. But its quite a strange thing, that rails allows
to set the protected attributes manually and then use the usual save
method to create a new record/object, but the same thing isn't allowed
while updating..I would have liked a flavor of Class.update() method
where it allows me to set the protected attributes (probably passing a
separate hash as to method call).

Anyways thanks for your answer!

What do you mean here?

-- fxn

I mean that say for example if I am creating a new record, I can do
the following.

# here is the mass-assignment for the non protected attributes.
@user= User.new(params[:user])
..
..
#now the manual assignment of protected attributes.
@user.picture = "my_avatar.jpg"

#then I save the object and store in db
if @user.save
...
else
..
end

You see its quite simple above to mass-assign the non protected
attributes and then manually the set the protected attributes and
finally save it to db.

However, in case of update, there is no similar technique like above
that will allow me to mass-assign the non-protected attributes and
then pickup the protected attributes and assign them manually, and
finally save to db.

If I use the update_all method i need to provide all the list of
attributes that i need to update and a condition. This is cumbersome
in case i have a lot of non-protected attributes against only one or
two protected attributes. Even if i have to update say only one
protected attribute, I have to manually assign all the other
attributes(may be 10 or 12) that i wish to update, that could have
been done through mass-assignment.

if i don't use a update_all method, I need to find the object first.

@user = User.find(id)

set its protected attributes

@user.picture="new_image.jpg"

and then update to db

@user.update_attributes(params[:user]) # done by mass-assignment.

But here, i need to find the record first....

Instead i would have wished that, i need not find the object first,
but still have the convenience as above.

Instead I would have wished a method say User.update(record_id,
params_attributes_hash, protected_attributes_hash)

here, "params_attributes_hash" is for mass-assignment. So I don't need
to care about, will be done automatically.
"protected_attributes_hash" would be the protected attributes that i
want to update.

Isn't this would be more convenient and efficient?

Let me know your thoughts, or if anything similar exists.

Penuel

The order is reversed, but for existing records you do something similar:

    @user = User.find(params[:id])
    @user.score += 50 # manual assignment to protected attribute
    if @user.update_attributes(params[:user]) # ignores protected keys
      ...
    else
      ...
    end

-- fxn

I have written a blog post on this subject:
http://lassebunk.dk/2010/07/09/mass-assigning-protected-attributes-in-rails/

Hope this helps.

Best regards,
Lasse