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 か月が経過しました。この問題が解決したかどうかはわかりませんが、それでも回答します。

昨日この問題が発生しましたが、同じバージョンDeviseを使用しています。Rails最初にコンソール ログを読み、ユーザーがいつ作成されたかを確認し、確認トークンが有効であることを確認してから、それを書き換えます。

デバッグ後、問題がupdateにあることがわかりましたafter create。なんで?unconfirmed_email更新ステートメントにも属性が追加されていることがわかりました。これは、更新時に電子メールが変更されることを意味します。メール欄を更新しないのが不思議です。そのため、 update ステートメントの直前に次のコードを追加します

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、データベースの電子メールは nil であり、電子メールが変更されたと考えてください。

最後に、更新により次のコールバックがトリガーされます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

after_create コールバックを使用する代わりに、'after_confirmation' メソッドを使用する必要があります。

def after_confirmation
  #your code here  
end
于 2015-02-12T13:59:51.657 に答える
0

この SO 投稿は、おそらく正しい方向に導くことができると思います。ユーザーのサインアップ時に「確認トークンが無効です」を工夫する

具体的には、このブログ投稿http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/

于 2014-03-07T00:45:20.960 に答える