Mailer Unable to Access Reset_Token in User Model

Mailer unable to access reset_token in User model

You're not storing the reset_token in the database - you're storing the reset_digest.

When you don't use workers, you're storing the reset_token in the User instance, then passing that same User instance to your mailer - hence the reset_token is still available.

When you use workers, your worker only has the User's ID, so it's reloading the User instance from the database. Because the reset_token isn't being stored in the database, it's coming back nil.

Either you should be saving the reset_token in the database, or your password email should be using reset_digest in the URL.

ActionMailer can't find reset_token, reports missing :id key

I figured it out! I had the answer all along; I had to store my reset_token in the database. I'll copy the answer from this Stack Overflow post below. Credit goes to sevenseacat for the answer.

When you don't use workers, you're storing the reset_token in the User
instance, then passing that same User instance to your mailer - hence
the reset_token is still available.

When you use workers, your worker only has the User's ID, so it's
reloading the User instance from the database. Because the reset_token
isn't being stored in the database, it's coming back nil.

Either you should be saving the reset_token in the database, or your
password email should be using reset_digest in the URL

After I changed my reset_token from a virtual attribute to a database column, the issue was resolved. My password reset emails are now being sent out.

EDIT (January 18, 2016)

I wanted to add a little extra information explaining why the reset_token solved the issue even though the error message claimed that the id was missing. In my password reset email, I generate the edit password reset action URL as follows:

<%= edit_password_resets_path(@user.reset_token) %>

The route for my edit password reset action is as follows:

edit_password_resets   GET   /password_resets/:id/edit

When creating a URL, the first parameter that you specify fills in the :id segment of the URL. In my case, @user.reset_token was being filled in for the id, causing the generated URL to be /password_resets/{reset token here}/edit. When the async job was trying to generate the URL, it was expecting a value to be specified for the id segment of the URL. I put my reset_token in for the id, and since reset_token was a virtual attribute and was equal to nil when ActiveJob ran, it threw an error since it was missing a value.

Rails 4 + Devise: Password Reset is always giving a Token is invalid error on the production server, but works fine locally.

Check the code in app/views/devise/mailer/reset_password_instructions.html.erb

The link should be generated with:

edit_password_url(@resource, :reset_password_token => @token)

If your view still uses this code, that will be the cause of the issue:

edit_password_url(@resource, :reset_password_token => @resource.password_reset_token)

Devise started storing hashes of the token, so the email needs to create the link using the real token (@token) rather than the hashed value stored in the database.

This change occurred in Devise in 143794d701

Why can't I use Related Model created with same request in Laravel?

You change a related model after loading the primary model, this will cause the relation of the primary model to be outdated, one could solve this by reloading the relationship.

In your case you could use:

$user->load('passwordResetLink');

before

Mail::to($user)->send(New \App\Mail\PasswordResetLink($user));

This will reload only the PasswordResetLink and prevent having to reload the whole object.

Why do I get an error when I try to save mongoose model?

Probably, user is null or undefined, so you should handle the user null condition.
Also findOne and save returns promise, so you need to add await keyword before them.

Also you have a typo in user schema password field, requires should be required .

let user = await User.findOne({
resetPasswordToken: resetPasswordToken,
resetPasswordExpire: { $gt: Date.now() },
});

if (user) {
// update password
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpire = undefined;
await user.save();
sendToken(user, 200, res);
} else {
res.status(400).send("No user found");
}

If you get the user null, you need to fix your query in findOne.

user.save() is not a function when i am trying to save the model

User.findOne will return a Promise. So you need to add await keyword.

const user = await User.findOne({email:req.body.email});

if(!user){
return next(new ErrorHander("User not found",404));

}
const resetToken = user.getResetPasswordToken

await user.save({ validateBeforeSave: false });

Password reset email using Rails devise is not changed

Follow the steps below to override Devise views. I would also recommend checking their documentation about overriding too.

Step 1

rails generate devise:views

Step 2 Add the following line under config/initializers/devise.rb

config.scoped_views = true

Step 3

Find the Devise views under devise/sessions/new and override them.



Related Topics



Leave a reply



Submit