How to selectively ignore some model validations?

Probably the best way is to redesign the app, so validations will be always required (eg introduce a Signup model associated with user).

But if you are looking for the simpler way then try.

# in user.rb attr_accessor :signing_up validates ..., :if => :signing_up

# in users_controller.rb def create User.create(params[:user].merge(:signing_up => true)) end

Or if the you want to skip those validateions for all already created users, then just use validates ..., :on => :update

Dmitry

Hi -

Thanks a lot, I like the simpler way you wrote out.

My question is, though, is that method vulnerable to mass-assignment attacks? I know that if it were attr_accessible, a user would be able to pass in a value for :signing_up and avoid having their data validated, but I don't know whether the same is true for attr_accessor.

Thanks again! Chris

Dmitry Sokurenko wrote:

It doesn't matter in that case cause even if a user will try to hack it, the merging of {:signing_up => true} will override hid value.

But to make it protected in all other parts of the app that use the User model: User attr_protected :signing_up

def create @user = User.new(params[:user]) @user.signing_up = true @user.save end

Dmitry

No, I think they don't work together, so just don't list :signing_up in the accesible attributes list.

Dmitry Sokurenko wrote:

No, I think they don't work together, so just don't list :signing_up in the accesible attributes list.

It is true that you cannot use both attr_accessible and attr_protected in the same model. Rails will throw a runtime error if both are specified on one model.

Ok, I've done some more reading and I think that I have this down now. Somebody tell me if I'm on the right/wrong path.

attr_accessible lists attributes that are open to mass-assignment. So, for security reasons, we shouldn't allow anything in attr_accessible that we wouldn't let the user define themselves.

Active Record automatically creates setter/getter methods for columns in databases - since my users table has a "name" column, for example, I can use @user.name in my models/views/controllers and it'll just work.

However, when I want to use a virtual attribute (something that isn't persisted in the database but that I still want to manipulate in Rails, like @user.signing_up), ActiveRecord can't do that for me, and I have to make setter/getter methods for that myself. I can make those with attr_accessor, but they won't be mass-assignable, and so they won't be vulnerable to mass-assignment attacks.

Finally, since the whitelist approach to security is better than the blacklist approach, attr_protected should just be ignored.

Do I have all that right?

1. Mass assignment doesn't care if the attributes are genreated by ActiveRecord, defined using attr-accessor, or implemented explicitly. It just doesn't allow some attributes to be mass assigned, so if the :secret is protected then   user.attributes = {:secret => ...}   user.update_attributes(:secret => ...)   User.create(:secret => ...) won't work, but   user.secret = ... will work always for protected & for not-protected attributes.

attr_accesseble & attr_protected can be used interchangeably, just use the one you like more, eg when User has 3 attributes: name, age & salary, then:   attr_accessible :name, :age is the same as   attr_protected :salary

In both case name & age will be accessible and salary will be protected.