這是一個非常有趣的問題。我認爲防止這個問題最簡單的方法(但不確定是否是最好的方法)只是改變電子郵件的唯一性驗證,並且只有在確認電子郵件後才能使用。
爲此,您應該在用戶模型中禁止validatable
模塊並手動實施驗證。
您可以從這裏複製所有默認驗證https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb,但是validates_uniqueness_of
。然後實現自己的電子郵件獨特驗證:
class User < ActiveRecord::Base
# do not include :validatable module here
devise :confirmable, :database_authenticatable, :registerable, ...
# your own validations
...
validates_uniqueness_of :email, allow_blank: true, if: lambda { |u| u.email_changed? && u.confirmed? }
...
編輯:
我的解決方法是不正確的。首先,如果電子郵件剛剛更改,則無法確認電子郵件。即使我的解決方案可行,並允許用戶使用現有的未經確認的電子郵件註冊,但當用戶嘗試確認他的電子郵件時,他仍然會失敗。
正確的解決方案是:
1)添加驗證,以防止其登記,如果電子郵件存在並確認。
2)重新定義#confirme!
方法,如果它存在於不確認電子郵件,確認
3)(未neсessary)重新定義#after_confirmation
方法與此電子郵件刪除所有其他未經證實的帳戶
class User < ActiveRecord::Base
# do not include :validatable module here
devise :confirmable, :database_authenticatable, :registerable # , ...
validate :confirmed_email_uniqueness
scope :with_confirmed_email, -> { where.not(confirmed_at: nil) }
scope :with_unconfirmed_email, -> { where(confirmed_at: nil) }
def confirm!
return false if confirmed_email_exists? # or add validation error, or raise some exception
super
end
private
def confirmed_email_uniqueness
errors.add(:email, "already exists") if email_changed? && confirmed_email_exists?
end
def confirmed_email_exists?
User.with_confirmed_email.where(email: self.email).exists?
end
protected
def after_confirmation
User.with_unconfirmed_email.where(email: self.email).destroy_all
super
end
...
感謝該方法。我正在研究替代方案,如果適用,我會接受你的答案。你不覺得這是一個重要的商業規則嗎? 顯然不是一般情況,但在我看來,Devise應該關心這一點。 你覺得呢? – maiconsanson 2014-10-11 13:46:23
我同意你的看法,我對這個問題感到非常驚訝。 – chumakoff 2014-10-11 15:50:32
我的解決方案不對。我有它編輯。 – chumakoff 2014-10-11 15:51:08