这是一个非常有趣的问题。我认为防止这个问题最简单的方法(但不确定是否是最好的方法)只是改变电子邮件的唯一性验证,并且只有在确认电子邮件后才能使用。
为此,您应该在用户模型中禁止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