ActionMailer 找不到 reset_token,报告缺少 :id 键
ActionMailer can't find reset_token, reports missing :id key
我正在使用 Delayed Job 作为我的 ActiveJob
排队后端,我正在尝试使用 ActionMailer
的 deliver_later
方法发送电子邮件。我相信我已经正确设置了所有 Delayed Job 的设置,并且我是 运行 我的开发机器上的后台工作者。
当我发送密码重置电子邮件时,我收到以下错误:
[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=>"user@example.com", :id=> nil} missing required keys: [:id]
这是我发送密码重置电子邮件的方式。这位于我的 User
模型中:
def send_password_reset_email
UserMailer.password_reset(self).deliver_later
end
我的密码重置设置与 上的设置非常相似,因为我没有将 reset_token
存储在数据库中,而是将其作为虚拟属性,我认为可能是我的问题,但我想尽可能避免存储该值。有没有办法可以将生成的 reset_token
传递给延迟作业工作人员?也有可能我的问题与其他问题有关。
如有任何帮助,我们将不胜感激!
我想通了!我一直都有答案;我必须将 reset_token
存储在数据库中。我将从下面的 中复制答案。感谢 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
从虚拟属性更改为数据库列后,问题就解决了。我的密码重置邮件正在发送中。
编辑(2016 年 1 月 18 日)
我想添加一些额外的信息来解释为什么 reset_token
解决了问题,即使错误消息声称缺少 id
。在我的密码重置电子邮件中,我生成 edit
密码重置操作 URL,如下所示:
<%= 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
是一个虚拟属性,当 ActiveJob
运行 时等于 nil
,它由于缺少值而引发错误。
我只是想自己解决一个类似的问题,但得出了一个略有不同的解决方案。为避免将重置令牌存储在数据库中,您可以重构 UserMailer.password_reset(self)
以采用两个参数 UserMailer.password_reset(self, self.reset_token)
。然后创建两个实例变量传递给邮件程序模板:
@user = user
@reset_token = reset_token
最后在邮件程序模板中,您可以这样做:
<%= edit_password_resets_path(@reset_token) %>`
我正在使用 Delayed Job 作为我的 ActiveJob
排队后端,我正在尝试使用 ActionMailer
的 deliver_later
方法发送电子邮件。我相信我已经正确设置了所有 Delayed Job 的设置,并且我是 运行 我的开发机器上的后台工作者。
当我发送密码重置电子邮件时,我收到以下错误:
[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=>"user@example.com", :id=> nil} missing required keys: [:id]
这是我发送密码重置电子邮件的方式。这位于我的 User
模型中:
def send_password_reset_email
UserMailer.password_reset(self).deliver_later
end
我的密码重置设置与 reset_token
存储在数据库中,而是将其作为虚拟属性,我认为可能是我的问题,但我想尽可能避免存储该值。有没有办法可以将生成的 reset_token
传递给延迟作业工作人员?也有可能我的问题与其他问题有关。
如有任何帮助,我们将不胜感激!
我想通了!我一直都有答案;我必须将 reset_token
存储在数据库中。我将从下面的
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 thereset_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 usingreset_digest
in the URL
我将 reset_token
从虚拟属性更改为数据库列后,问题就解决了。我的密码重置邮件正在发送中。
编辑(2016 年 1 月 18 日)
我想添加一些额外的信息来解释为什么 reset_token
解决了问题,即使错误消息声称缺少 id
。在我的密码重置电子邮件中,我生成 edit
密码重置操作 URL,如下所示:
<%= 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
是一个虚拟属性,当 ActiveJob
运行 时等于 nil
,它由于缺少值而引发错误。
我只是想自己解决一个类似的问题,但得出了一个略有不同的解决方案。为避免将重置令牌存储在数据库中,您可以重构 UserMailer.password_reset(self)
以采用两个参数 UserMailer.password_reset(self, self.reset_token)
。然后创建两个实例变量传递给邮件程序模板:
@user = user
@reset_token = reset_token
最后在邮件程序模板中,您可以这样做:
<%= edit_password_resets_path(@reset_token) %>`