Ricodigo's blog

We write delicious code.

An Alternative to Attr_accessible to Keep Updates Safe

If you’ve read the news today on HN, someone has been pushing commits to the rails repo by using a mass assignment trick. The problem is now fixed although the drama is still ongoing.

There’s been a great proposal by wycatz posted here. We do it another way using mongoid_ext’s safe_update method that you can check here, this is how it looks like:

module MongoidExt
  module Update
    def safe_update(white_list, values)
      white_list.each do |key|
        send("#{key}=", values[key]) if values.has_key?(key)
      end
    end
  end
end

It’s just simple white-listing but it’s very explicit and straight forward to use. This is what goes into the update method in shapado for example:

 @question.updated_by = current_user
 @question.safe_update(%w[title body language], params[:question])

So only the params specified in safe_update are being saved. If I add a new field to the model, I have to explicitely add it to the safe_update method, otherwise it won’t get saved. It requires a bit of extra work but the good thing is that I know at all time what’s being sent and updated everytime I look at that method and it forces me to maintain it correctly. It’s not incompatible with scaffolding as it could still add the default fields to safe_update on generating the controller methods.

Update: As reported in the comments and on Twitter by DHH himself, using slice on update_attributes would have the same effect. So you could just do:

@question.update_attributes(params[:question].slice(:title, :body, :language))

Comments