Rails has a great feature called protected attributes which you can set like this:
class User < ActiveRecord:Base attr_protected :account_id end
Or you can use the inverted versions (which I prefer) where you set which attributes are accessible, like this:
attr_accessible :name, :email
What this does is that it tells Rails which attributes can be used in mass-assignment like this:
User.create(:name => "Piyush", :email => "firstname.lastname@example.org")
or what’s used more:
Then some malicious hacker cannot use mass-assignment to manually set the account_id.
If you try to assign to protected attributes you’ll get the following warning:
WARNING: Can't mass-assign these protected attributes: account_id
But the problem is: What if I’m no hacker, but I should have unlimited access, for example as an administrator? Then I can’t mass-assign to any protected attributes. Then I’d need to do something like this:
u = User.new(params[:user]) u.account_id = params[:user][:account_id]
Not very pretty.
What I’ve done is that I’ve created an extension to some of the methods taking mass-assignment and added an optional parameter calledguard_protected_attributes which has a default value of true.
# config/initializers/unprotected_attributes.rb class ActiveRecord::Base def update_attributes_with_unprotected(attributes, guard_protected_attributes = true) send :attributes=, attributes, guard_protected_attributes save end alias_method_chain :update_attributes, :unprotected end
We can do this because the native ActiveRecord::Base#attributes= can also be called with guard_unprotected_attributes.
Now you can call update_attributes like this:
user = User.find(3) user.update_attributes(params[:user], false)
and it will also assign the protected attributes.
I have made extensions to create, new, update_attributes, andupdate_attributes!.
The ugly part, however, is that to make it work, I had to copy the functions in their entirety which could potentially mean that if you use it on a Rails version other than exactly 2.3.8 it might not work. Sorry for that.