2

我在 Rails 4.0.3 应用程序上使用 Devise 3.2.3

在我的用户模型中,我有一个after_create: subscribe为新用户订阅时事通讯的回调。每次新用户尝试确认他们的电子邮件时,我都会介绍此回调,然后他们会收到confirmation token is invalid消息。尽管如此,重新发送确认电子邮件中的确认链接仍然有效。

我显然可以避免使用:after_create回调,但这很痛苦。

User.rb:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :trackable, :validatable,
         :confirmable, :rememberable

    has_many :things
    belongs_to :city
    validates_presence_of :city_id
  validates :email, :presence => true, :email => true

  after_create :subscribe


  def subscribe(frequency = :weekly)
    if [:weekly, :monthly].include? frequency
      response = Rails.configuration.mailchimp.lists.subscribe({
        id:           get_list_id(frequency),
        email:        { email: email },
        merge_vars:   { HASH: hashify(frequency), USER_ID: id }, # generate approptiate hash
        double_optin: false
      })
      # response
    end
    update_attributes(newsletter_frequency: frequency.to_s)
    response
  end
end
4

3 回答 3

1

已经4个月了,不知道你有没有解决这个问题,但我还是会回答的。

我昨天遇到了这个问题,我用的是DeviseRails版本一样的。首先我阅读了控制台日志,发现用户创建的时间,确认令牌是有效的,然后,它被重写了。

调试后发现问题出updateafter create. 为什么?我发现更新语句还添加了unconfirmed_email属性,这意味着更新时,电子邮件被更改。这很奇怪,因为我不更新电子邮件列。所以我在更新语句之前添加了以下代码

changed_attributes.each do |attr, origin|
  puts "#{attr}: #{origin.inspect} => #{self.send(attr)}"
end

结果是:

id: nil => 108
email: "" => d33faf@qq.com

看?更新的时候,邮箱地址变了,甚至id创建了,好像还没有创建记录。这很奇怪,因为记录应该是被创建的,因为它被调用了after create

一切都是关于transactioncreate行动被包围在一个完整的交易中。after create仍在此事务中,并且由于该insert语句尚未提交,因此Rails认为数据库中的电子邮件为零并且电子邮件已更改。

所以到了最后,更新触发了以下回调Devise

before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, if: :postpone_email_change?

然后它发现电子邮件已更改,因此它重新生成了确认令牌。

好的,我们怎样才能避免呢?

最简单的方法是使用update_columns而不是update,它不会触发before_update回调,但会绕过验证。

更好的方法是使用after_commit on: :create而不是after_create,因为它将在事务之后执行。但问题是目前它有一个错误。请参阅我在 Github 上创建的问题:https ://github.com/rails/rails/issues/16286 ,以及关于 SO:在更新 after_commit 中的属性时防止无限循环,:on => :create

于 2014-07-25T04:43:25.173 回答
0

我认为这篇 SO 帖子可能会引导您朝着正确的方向前进。用户注册时设计“确认令牌无效”

特别是这篇博文 http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/

于 2014-03-07T00:45:20.960 回答
0

您需要使用 'after_confirmation' 方法而不是使用 after_create 回调。

def after_confirmation
  #your code here  
end
于 2015-02-12T13:59:51.657 回答