Ruby on Rails / Devise - Bypassing custom validation option in model when resetting password
In my project, I altered the registration form in Devise to add an :agree option via an accessor (user must accept terms of service to register, etc). If they don't agree, it doesn't validate.
That caused a problem when a user tried to edit their account information as it seeked out the :agree validation, but I was able to add an 'unless' clause and added another accessor called :signed_in that is defined in the controller (I couldn't figure out how to get the model to determine if the user was signed in or not, devise's helpers wouldn't work for me in it). The relevant portions of my User model and users_c开发者_运维知识库ontroller look like...
user.rb
validates :agree, :term_agreement => TRUE, :unless => :signed_in
users_controller.rb
def update
@user = User.find(params[:id])
if user_signed_in?
@user.signed_in = params[:user]
end
[...]
end
So, it all works fine...the "agree" validation overrides when a user is already signed in. However, I have to figure out the best way to override another scenario...when a user resets their password and needs to change it.
I was testing user accounts and tried to reset my password on one account, however I was hit with the :agree validation...now I have to figure out a way to override that. I noticed the Change your password form has a hidden field value of :reset_password_token, however I tried :unless => :reset_password_token but it wouldn't work.
So what is the best way of accomplishing this? On top of that, how can I have an either / or condition (unless :signed_in or :reset_password, etc) for that :unless clause?
So, you need to validate the acceptance of terms when the record is created?
class User < ActiveRecord::Base
validates :agree, :acceptance => true, :on => :create
end
:on => :create
will only perform that validation when the record is being created—much like Brandon's answer, but without redundant code.
This will also obviate the need for your controllers to worry about if a user is signed in or not.
I prefer to base these kinds of things on whether or not the record is new (which is the only time the user will be "signing up").
class User < ActiveRecord::Base
validates :agree, :term_agreement => TRUE, :if => :signing_up?
# Return true if the user is currently signing up
def signing_up?
new_record?
end
end
The key is to keep in mind that the value of :if
and :unless
is "a method, proc or string to call to determine if the validation should [or should not] occur"--so you're free to define methods on your model for this purpose.
I fixed this by configuring devise to update the password attributes directing if validation failed, but only if the password attributes are error free.
See my answer here:
Validation errors are triggered when I'm trying to reset password
精彩评论