【问题标题】:Rails devise reset :confirmed_at field when user email is changed更改用户电子邮件时,Rails 设计重置:confirmed_at 字段
【发布时间】:2020-08-01 02:15:51
【问题描述】:

当用户更改其电子邮件地址时,不会确认新电子邮件。但是设计不会更新/重置 confirm_at 字段。

我试过了:

before_update :updateEmailConfirmed, if: :email_changed?

def updateEmailConfirmed
  # check if there is an unconfirmed_email
  user = User.find(id)
  if !user.unconfirmed_email.nil?
    # set confirmed_at to nil
    self.update!(confirmed_at:nil)
  end
end

我了解:confirmed_at 字段用于任何确认,因此它按预期工作。但是,我使用此字段来跟踪以查看电子邮件是否已通过验证。

目前,我在我的用户模型中添加了一个名为 :email_confirmed 的额外字段,类型为 bool,我将其设置为 true/false,具体取决于当前的 :email 字段是否已经过验证。

我的问题是,Devise 模块中是否有任何内置功能可以让我在不向我的用户表中引入任何新列并修改我的用户类的情况下执行此操作。

更新1。)

以下是为我的用户模型设置的标签:

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable,
     :confirmable

  protected
  def confirmation_required?
    false
  end
end

这是我的用户表的样子:

create_table "users", force: :cascade do |t|
  t.string "email", default: "", null: false
  t.string "encrypted_password", default: "", null: false
  t.string "reset_password_token"
  t.datetime "reset_password_sent_at"
  t.datetime "remember_created_at"
  t.integer "sign_in_count", default: 0, null: false
  t.datetime "current_sign_in_at"
  t.datetime "last_sign_in_at"
  t.string "current_sign_in_ip"
  t.string "last_sign_in_ip"
  t.string "confirmation_token"
  t.datetime "confirmed_at"
  t.datetime "confirmation_sent_at"
  t.string "unconfirmed_email"
  t.boolean "verified", default: false
  t.index ["confirmation_token"], name: "index_users_on_confirmation_token", 
    unique: true
  t.index ["email"], name: "index_users_on_email", unique: true
  t.index ["reset_password_token"], name: 
    "index_users_on_reset_password_token", unique: true
end

【问题讨论】:

  • 你使用:confirmable?
  • 是的,我将更新问题以显示我的用户表和用户模型。

标签: ruby-on-rails ruby devise


【解决方案1】:

我能想到的最好的方法是覆盖 Devise 提供的 Devise::MailerConfirmation::Controller

我意识到我可以在发送到用户电子邮件的confirmation_url 中传递一个类型参数。

class DeviseMailer < Devise::Mailer
  def confirmation_instructions(record, token, opts={})

    # determine if this request is to change the email
    # or verify the existing email
    if !record.unconfirmed_email.nil?
      type = "change_email"
    else
      type = "verify_email"
    end

    # get the link for the confirmation link and append 
    # the type paramater to the end
    confirmation_link = Rails.application
      .routes.url_helpers
      .user_confirmation_url(confirmation_token: token).to_s + "&type="+type.to_s
    .
    .
    .
    # send email with new confirmation link
  end
end

然后在另一端,当有人点击确认链接时,我可以通过查看参数来区分请求的类型:

class ConfirmationsController < Devise::ConfirmationsController
  def show
    # confirm user 
    self.resource = resource_class.confirm_by_token(params[:confirmation_token])

    if resource.errors.empty?

      # sign in user if they are not already signed in
      sign_in(resource_name, resource)

      # find out what kind of request this confirmation was for
      type = params[:type]
      if type == "verify_email"
        flash[:confirmed] = "Email successfully confirmed!"

        # update verified field which is used to keep track if the :email field has been verified
        current_user.update(verified:true)

      elsif type == "change_email"
        flash[:confirmed] = "Email successfully updated!"

        # update verified field which is used to keep track if the :email field has been verified
        current_user.update(verified:false)

        # send confirmation instructions for this new email so we can verify it
        current_user.send_confirmation_instructions
      end

      respond_with_navigational(resource){ redirect_to root_path }
    else
      p resource.errors
      flash[:unconfirmed] = "Something went wrong trying to confirm your email? Contact contact@email.com"
      respond_with_navigational(resource.errors, status: :unprocessable_entity){ redirect_to edit_user_registration_path }
    end
  end

  private
  def after_confirmation_path_for(resource_name, resource)
    sign_in(resource) # In case you want to sign in the user
    root_path
  end

end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    相关资源
    最近更新 更多