While it is always good to have attr_accessible or attr_protected set in a ActiveRecord model class to protect it from abuse when updating any object of that class from the params of a Rails controller.

But what to do when you have that attr_accessible but you won’t let a certain action in your controller even edit all of those accessible fields. Maybe because you’re paranoid or just a think that an action should only be allowed to edit what they was invented for, there might be some good reasons.

We faced this problem lately and came up with that solution:

1
2
3
4
5
6
7
8
9
10
11
12
class ActiveRecord::Base
  def update_by_params(params, *fields)
    self.attributes = params.reject
        {|key,value| !fields.index key.to_sym}
    self.save
  end
  def update_by_params!(params, *fields)
    self.attributes = params.reject
        {|key,value| !fields.index key.to_sym}
    self.save!
  end
end

The update_by_params instance method on the ActiveRecord::Base class let you do something like this:

1
2
3
4
5
6
# ... in a controller ...
def change_password
  @current_user.update_by_params(params[:user],
      :password, :password_confirmation)
  redirect_to frontpage_url
end

And then the user won’t be able to edit his address with a hacked password change form, even if he is allowed to do so in his profile.

The method will save the object after the update. To handle errors on saving there are (as usual in Rails) two specifications of this method available, one with a ! at the end which just uses save! to save the object and one without the ! which uses save. So update_by_params! will throw an error if the save fails while update_by_params just returns false.

Have fun with that.

Yours,

Thorben
FEtMab-Team

Related posts