ruby-on-rails - 设计确认在第一次发送时无效

标签 ruby-on-rails devise ruby-on-rails-4 devise-confirmable

我有一个使用 :confirmable 和 Devise 3.2.2 的 Rails 4 应用程序,我遇到了发送无效确认 token 的问题,但只是第一次 .在您重新发送确认 token 后,该链接将起作用。

相关路线:

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)

引用的 Controller 是:

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

最佳答案

在注册 create 操作完成之前,似乎有什么东西导致您的用户立即更新和重新保存(包括生成新的确认 token )。看看你的要点:

  • 第 5 行显示了对具有电子邮件地址的现有用户的设计检查
  • 第 6 行显示设计检查它刚刚生成的确认 token 是否已经存在于某些其他用户(显然它们需要是唯一的)
  • 第 9 行显示新的用户记录被插入到您的数据库中
  • 第 11 行看起来 devise 刚刚生成了一个新的确认 token ,并且正在检查这个新 token 是否已经在使用中。
  • 第 14 行随后显示正在保存的更新的用户详细信息,包括这个新的确认 token 。我注意到第 9 行的初始插入中没有 tos_accepted_at 字段。还设置了 unconfirmed_email 字段,并且 confirmation_sent_at 字段比第 9 行中保存的字段晚 1 秒;这可能只是由于正常的 :confirmable 行为,尽管我很惊讶设计没有发现电子邮件地址与现有(未确认)相同的事实并且没有打扰。

问题是为什么用户被保存了两次?看起来您已经添加了 tos_accepted_at 属性。某处是否有一些代码(后过滤器?)重新保存用户,包括此属性以及所有其他属性,然后再次触发设计的可确认逻辑?说到这一点,我最感兴趣的是它没有立即导致发送第二封电子邮件(带有有效的确认 token ),因为 confirmation_sent_at 时间戳发生了变化。

我注意到也有一些版本跟踪正在进行,从其他 INSERT 判断,尽管它看起来不会干扰。

作为额外的健全性检查,如果您可以让 Rails 控制台对您期望的确认 token 进行加密,您会发现加密版本与要点第 6 行的版本相匹配,然后在第 9 行的数据库。我不能尝试这个,因为它取决于你的 rails secret (参见 devise/toekn_generator.rb 中的 Devise::TokenGenerator)。无论如何,没有必要,但会确认原始确认 token 永远不会起作用。

我假设重新发送有效,因为这只是正常情况(没有双重保存,没有额外的 tos_accepted_at 字段等)

更新

正如评论中所讨论的,问题确实出在 tos_accepted_at 属性上。它正在使用 after_create 回调中的 update_attribute() 进行更新。由于有点不清楚的原因,这似乎弄脏了所有属性,所以它们也都被保存了(update_attribute 如果它们变脏了,也会保存所有其他属性)并设计生成一个新的确认 token 作为此过程的一部分(尽管我们认为不应该这样做,因为电子邮件地址实际上并没有改变!)。将保存更新的 tos_accepted_at 的过滤器更改为 before_save 过滤器而不是 after_create 通过确保用户仅保存一次来避免问题,因为before_save 显然发生在第一次保存之前,而 after_create 显然发生在将用户插入数据库的保存之后。

关于ruby-on-rails - 设计确认在第一次发送时无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21567625/

相关文章:

ruby-on-rails - 可以在 Rails 中有条件地链接作用域吗?

ruby-on-rails - Rails authlogic : How to make Levels?

ruby-on-rails - 在 Rails 中使用 Devise gem 时如何创建没有电子邮件和密码的用户?

ruby-on-rails - 编写自定义 OmniAuth 策略

javascript - 如何在单击按钮时打开下拉菜单?

javascript - Rails 中提交的表单数据错误

mysql - ActiveRecord 错误 : SAVEPOINT active_record_1 does not exist

ruby-on-rails - Rails 3 ActiveRecord 方法链,在幕后

ruby-on-rails - devise-async 不适用于 sidekiq

ruby-on-rails - 使用 Devise 在具有子域的 Multi-Tenancy 站点上自动登录用户