2

我使用Delayed Job作为我的ActiveJob排队后端,并且我试图使用ActionMailerdeliver_later方法发送电子邮件。我相信我已经完成了Delayed Job的所有设置,并且在我的开发机器上运行了一个后台工作者。ActionMailer无法找到reset_token,报告缺失:id密钥

当我发送密码重置电子邮件,我收到以下错误:

[Worker(host:Computer pid:7240)] Job ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper (id=1) FAILED (5 prior attempts) with ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"password_resets", :email=>"[email protected]", :id=> nil} missing required keys: [:id]

这里是我如何发出的密码重置邮件。这个位于我User模型:

def send_password_reset_email 
    UserMailer.password_reset(self).deliver_later 
end 

我的密码重置设置非常相似,在该this SO post一个我不存储我的数据库reset_token,而是把它作为一个虚拟的属性,我认为这可能是我的问题,但我想尽可能避免存储该值。有没有办法将生成的reset_token传递给Delayed Job worker?我的问题也可能与其他问题有关。

任何帮助将不胜感激!

回答

0

我想通了!我一直都有答案。我必须将我的reset_token存储在数据库中。我会复制下面的this Stack Overflow post的答案。积分为sevenseacat为答案。

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

将我的reset_token从虚拟属性更改为数据库列后,问题已解决。我的密码重置电子邮件现在正在发送。

EDIT(2016年1月18日)

我想添加一些额外的信息来解释为什么reset_token解决即使错误消息声称id失踪的问题。在我的密码重置电子邮件,我产生了edit密码重置行动网址如下:

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

我改密码重置操作的路线如下:

edit_password_resets GET /password_resets/:id/edit 

当创建一个URL,第一您指定的参数将填充URL的:id部分。在我的情况下,@user.reset_token填写为id,导致生成的URL为/password_resets/{reset token here}/edit。当异步作业尝试生成URL时,它希望为URL的id段指定一个值。我把我的reset_token在为id,由于reset_token是一个虚拟的属性,等于nilActiveJob跑了,它因为它缺少一个值抛出一个错误。

0

我只是想解决类似的问题,我来到一个稍微不同的解决方案。为了避免将重置令牌存储在数据库中,您可以重构UserMailer.password_reset(self)以获取两个参数UserMailer.password_reset(self, self.reset_token)。然后创建两个实例变量传递到邮件模板:

@user = user 
@reset_token = reset_token 
在邮件模板本身

最后,你可以这样做:

<%= edit_password_resets_path(@reset_token) %>` 
+0

感谢您分享您的解决方案。在我写下我的解决方案后不久,我走了一条类似于此的路线。我创建了一个单独的作业,并将密码重置令牌传递到作业有效内容中,如下所示:此代码在'User'模型中调用。 'SendPasswordResetJob.perform_later(self.id,self.password_reset_token)' – Alexander