我使用:confirmable
创建了一个带有Devise 3.2.2的Rails 4应用程序,并且遇到了发送无效确认令牌的问题,但只是第一次。重新发送确认令牌后,该链接将起作用。
相关路线:
devise_for :users, skip: [:sessions, :passwords, :confirmations, :unlocks, :registrations, :invitations]
as :user do
...
# joining
get '/register' => 'devise/registrations#new', as: 'new_user_registration'
post '/register' => 'devise/registrations#create', as: 'user_registration'
...
end
...以及有问题的邮件模板:
<p>Welcome <%= @email %>!</p>
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) %></p>
据我所知,一切都是非常标准的票价,事实上它只是在最初创建而不是重新发送时失败,这是相当混乱的。
- 更新 -
点击链接后,我在开发日志中收到以下内容:
Started GET "/account/confirm?confirmation_token=3bQP-EvYJPv74s9AMz63" for 127.0.0.1 at 2014-02-07 12:26:10 -0500
Processing by Users::ConfirmationsController#show as HTML
Parameters: {"confirmation_token"=>"3bQP-EvYJPv74s9AMz63"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = 'e191b48746f15014beb32073f08de3c7aa13a2282216f089fa71d083901b3dca' ORDER BY "users"."id" ASC LIMIT 1
Rendered devise/shared/_links.slim (1.2ms)
Rendered devise/confirmations/new.html.slim within layouts/devise (7.0ms)
Rendered layouts/_jquery.slim (1.0ms)
Completed 200 OK in 32ms (Views: 23.4ms | ActiveRecord: 0.4ms)
引用的控制器是:
class Users::ConfirmationsController < Devise::ConfirmationsController
protected
def after_confirmation_path_for(resource_name, resource)
if signed_in?
signed_in_root_path(resource)
else
new_session_path(resource_name, email: resource.email)
end
end
end
- 更新2 -
以下是整个注册过程中日志的要点: https://gist.github.com/jbender/bbe079c2dd3fa2d1e664
答案 0 :(得分:6)
在注册create
操作完成之前,看起来有些事情会导致您的用户立即更新并重新保存(包括生成新的确认令牌)。看看你的要点:
问题是为什么用户会被保存两次?看起来你已经添加了一个tos_accepted_at属性。是否有某些代码(后过滤器?)重新保存用户,包括此属性以及所有其他属性,然后再次触发设计的可确认逻辑?说到这一点,我最感兴趣的是它没有立即导致发送第二封电子邮件(确认令牌有效),因为confirm_sent_at时间戳发生了变化。
我注意到有一些版本跟踪正在进行,从其他INSERT判断,虽然它看起来不会干扰。
作为一项额外的健全性检查,如果您可以强制使用rails控制台加密您所期望的确认令牌,您会发现加密版本与您要点的第6行的版本相匹配,然后将其覆盖第9行的db。我不能尝试这个,因为它取决于你的rails秘密(参见devise / toekn_generator.rb中的Devise :: TokenGenerator)。无论如何,没有必要,但会确认原始确认令牌永远不会起作用。
我认为重发是有效的,因为它只是正常情况(没有双重保存,没有额外的tos_accepted_at字段等)。
<强>更新强>
正如评论中所讨论的,问题确实是tos_accepted_at属性。它在update_attribute()
回调中使用after_create
进行了更新。由于有点不清楚的原因,这似乎弄脏了所有属性,所以它们都被保存(如果它们是脏的,update_attribute
也保存所有其他属性)并设计生成新的确认令牌作为这个过程(虽然我们不认为它应该有,因为电子邮件地址实际上没有改变!)。将保存已更新的tos_accepted_at
的过滤器更改为before_save
过滤器而不是after_create
,可以确保用户只保存一次,从而避免了问题,因为before_save
显然在此之前发生了首先保存而不是after_create
,这当然是在将用户插入数据库的保存之后发生的。
答案 1 :(得分:-1)
根据路线文件,我假设你已经覆盖了注册控制器 我的预感是你在注册中做了一些不正确的事情#create action。具体来说,在创建用户记录时,confirm_token未正确存储在用户记录中。
我的理论是:
confirmable.rb第278行
返回false,因为第277行没有找到具有提供的令牌的用户,因为它没有正确存储。因此,277创建了一个新的用户记录,并且278返回false
。
当您完成重新发送流程时,整个令牌生成/存储过程将再次执行la confirmable.rb并在confirmations_controller.rb中确认#create。这修复了注册#create。
您可以验证在初始创建时,您的用户模型是否正确存储了confirmation_token?