Сброс устройства Rails: поле Verified_at при изменении электронной почты пользователя - PullRequest
0 голосов
/ 18 апреля 2020

Когда пользователь меняет свой адрес электронной почты, новый адрес электронной почты не подтверждается. Однако devise не обновляет / сбрасывает поле Verified_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, которое позволит мне делать это, не вводя новые столбцы в мой Таблица пользователей и изменение моего класса User.

Update1.)

Вот теги, установленные для моей модели User:

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

Так выглядит моя таблица User. :

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

1 Ответ

0 голосов
/ 18 апреля 2020

Лучшее, о чем я мог подумать, это переопределение Devise::Mailer и Confirmation::Controller, предоставляемых Devise.

Я понял, что могу передать параметр типа внутри подтверждения_урла, который отправляется на электронную почту пользователя.

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

Затем, на другом конце, когда кто-то нажимает на ссылки подтверждения, я могу различить guish тип запроса, просмотрев параметры:

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
...