Rails devise reset password fails if user record contains invalid data - ruby-on-rails

I have an existing application in production where we have added new mandatory fields to the user record. As a result, the forgot password function is failing. I believe the failure occurs in the following method in recoverable.rb
# Update password saving the record and clearing token. Returns true if
# the passwords are valid and the record was saved, false otherwise.
def reset_password(new_password, new_password_confirmation)
if new_password.present?
self.password = new_password
self.password_confirmation = new_password_confirmation
save
else
errors.add(:password, :blank)
false
end
end
The new attributes cannot be generated mechanically. Only the user himself will know the correct values. Does anyone know of a way to get around this problem?
The only idea that I've come up with so far is as follows:
use a rake script to populate the new fields with values that I know would never occur in real life but would be accepted by the model validation rule
when the user logs in, detect if the user record contains invalid data and force them to do an update. In the user edit form, I would use some javascript to change the bogus values to blank.

You could use a custom validation context to make sure the validations on these added fields are only run when a user edits their profile, but skipped when (for example) Devise saves the user record.
In the User model, add an on:-clause to these validations
validates_presence_of :recently_added_mandatory_field, on: :user_updates_profile
And in the appropriate controller action, add this validation context when calling #valid? or #save:
# Existing code uses `#user.valid?` -> change to:
if #user.valid?(:user_updates_profile)
…
# Existing code uses `#user.save` -> change to:
if #user.save(context: :user_updates_profile)
…
See here for a full description of validation contexts: https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates

Related

custom validation on django-allauth

I'm using dj-allauth on my django app. When people sign up to my django project/app, I want to check that the domain on their email matches mydomain.com. Is this possible? I think I can do it by changing the signup form. I've tried the following which doesn't seem to do anything when I submit the signup form. There aren't any errors. It isn't checking for the domain, it's prompting for the user's nickname and then appending the domain automatically.
forms.py
class VSBSignupForm(SignupForm):
def save(self, request):
# Ensure you call the parent classes save.
# .save() returns a User object.
user = super(VSBSignupForm, self).save(request)
user.email_address = user.username + "#mydomain.com"
user.save()
# You must return the original result.
return user
settings.py
ACCOUNT_FORMS = {'signup': 'myapp.forms.VSBSignupForm'}
I changed the template for the signup.html such that it asks for the nickname and password, but not the email address.
edit I tried putting a print statement in the form save method and it didn't print anything in the shell, which makes me think the form isn't being used.

Rails: remember user input in devise registration form after error

I'm using Rails 3.2.16 and devise 3.2.2.
I've added a (hidden) field account_level to my devise registration form. This is populated by a query string in the URL depending on what plan the user chooses.
If the user has an error with the registration form, such as the password do not match or a required field isn't filled in, the registration page then reloads with the errors present. However, the account_level field is now blank and the url does not have the query string on it for me to pull the data from it.
How can I have rails "remember" what was in that field after a page reload if a error occurs?
Bonus sanity check question: Is there a better way to pass which plan the user has choose when registering?
----------- Update -----------
I used a combination of the answers from Shamsul and aelor. I ended up grabbing the value of the query string and saving it in a cookie using javascript. If the page then reloads from a validation error, and the query string on the URL is no longer there, I look for the cookie that was set and grab the value from there to populate the hidden field.
I want to keep as much on the front end, which is why I opted for the JS solution. I also felt like cookies are a more tried and tested vs local storage.
use localStorage.
you can save your plan , when the user clicks it.
localStorage.setItem('plan','premium');
then you can check for the the item and fill up the hidden field.
if(localStorage.getItem('plan') != null){
$('#hiddeninput').val(localStorage.getItem('plan'));
}
and you can delete that plan whenever you like by using
localStorage.removeItem('plan');
In registrations_controller.rb of devise
Store account_level field in a cookies as
def new
if params[:account_level]
cookies[:account_level] = params[:account_level]
end
#other code
end
def create
if resource.save
unless cookies[:account_level].nil?
cookies.delete(:account_level)
#do other coding
end
end
end
In this way account_level field will not blank after reloaing the page.

Devise log in with one more condition to check

I´m using devise gem in a rails 4 app and I have in my user table a column called valid that by default is false, when the user registers in the site it should send me a email with the information about them and approve it, and put that valid column in true. So then in the log in action it will check that valid is true and let them login to the site.
My question is how modify that login action that takes care of the valid column in users table.
You should look at adding :confirmable to your User model, it may take care of most of what you are looking to do.
Otherwise, if you want to modify whether someone can login, look at the wiki on how to customize account validation.
From the wiki:
def active_for_authentication?
# Uncomment the below debug statement to view the properties of the returned
# self model values.
# logger.debug self.to_yaml
super && account_active?
end

First Argument cannot be nil when trying to override Devise's Confirmations Controller

I'm trying to implement the override method outlined here Devise- Override Confirmation. My version of rails is 4 and ruby is 2.0. My implementation involves multiple resources, so i'm coding this override to a specific resource, a rider.
The show action is rendering correctly, and i can enter my password. But when i submit the form i get the following error message
First argument in form cannot contain nil or be empty
I walked through the code with a debugger with watches for #confirmable and self.resource which are set in the with_unconfirmed_confirmable and do_show methods of the controller respectively, and it seems that while rendering the show template in the do_show method both #confirmable and self.resource are set to the user trying to confirm. However both are set to nil when updating the confirmation.
Since the code is rather long, i've put my controller, show template, and the devise related code in a gist.
EDIT in Response to the Comment
I am storing the confirmation token in the form as a hidden field. It's set to the correct value (when i use it to query the db i get the user i expect).
Once again walking through it with a debugger, I noticed that the value of the confirmation token seems to be regenerated to a different toke during the update action, but it's correct in the request parameters.
{"rider"=>{"confirmation_token"=>"92f786e5270e3562aa48589cc6c36e083cc7a23a41bb55f92c338f381050ec8b"}, "commit"=>"Activate", "controller"=>"riders/confirmations", "action"=>"update"}
Because of that #confirmable is being set to nil.
So now i'm wondering why
#confirmation_token = Devise.token_generator.digest(User, :confirmation_token, #original_token) generating a brand new token on update, when the value of #original_token seems to be the same (based on the watches in my debugger).
I got this working for the non-default user by setting the confirmation token in a hidden field using the hidden_field_tag instead of f.input. Doing this prevented the confirmation_token from being overwritten during the update. I've updated the gist to reflect the changes.

Pass Account ID to New User During Sign Up

Currenntly, my application is designed using Devise for authentication. I have it so when the first user signs up, an account is created in an Accounts table and the account_id is passed to the User table. I also have it set so that each time a new account is created that user is tagged as an admin. Finally, I have it working where the admin can create new users.
My problem is that at the time the new users are created I need to have these users be assigned the same account_id as the admin to tie the users together. I can do this if I add an account_id field on the form and have the admin manually enter it. What I want to have is that this is automated in the background.
I tried many varieties without success. This is one of the unsuccesful attempts where I put the following in the user.rb
before_save :add_account_id_from_parent
def add_account_id_from_parent
return true unless self.users.present?
self.users.update_attribute(:account_id, 1)
end
I used the number "1" just to see if I could get anything automated and placed in that field.
Like I said manually everything works, but I want it so the acocunt_id is automatically added during sign up based on the admins account_id.
I'm a bit confused why you are calling self.users. If I understand correctly, you want to assign account_id to 1 after a new user is created (as a test). You can do that like this:
before_save :add_account_id_from_parent
def add_account_id_from_parent
self.account_id = 1
end
You don't need to actually update the record since this is assigned before save, and save will write the new value to the db.
Again I might be missing something, if so please clarify.
UPDATE:
If you're validating that account is present, you'll need to change the callback to a before_validation instead of before_save, like so:
before_validation :add_account_id_from_parent

Resources