【问题标题】:Validation errors are triggered when I'm trying to reset password尝试重置密码时触发验证错误
【发布时间】:2013-09-21 20:48:06
【问题描述】:

我正在使用 devise 进行身份验证,并且在设置完 devise 后,我在 users 表中添加了一些其他字段。用户只需输入电子邮件和密码即可注册,注册后用户可以编辑其个人资料。为此,我使用了 :on => update。但是现在当我尝试重置密码验证时会触发错误,例如名称不能为空等等。我正在使用设计并使用 registrations#edit 来重置密码。下面是我的用户模型。

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :dob, :phone, :address, :state, :city, :country, :photo

  has_attached_file :photo, :styles => { :small => "150x150>", :medium => "300x300>", :large => "500x500>" }
  has_many :blogs, :dependent => :destroy
  has_many :comments, :dependent => :destroy
  has_many :followers, :through => :blogs
  has_many :followings, :class_name => 'Follower', :foreign_key => 'user_id'
  has_many :following_blogs, :through => :followings, :source => :blog
  has_many :blog_followers, :through => :followers, :source => :user

  phone_regex = /^[0-9]+$/

  validates_attachment_size :photo, :less_than => 3.megabytes
  validates_attachment_content_type :photo, :content_type => ['image/jpeg','image/png','image/jpg','image/gif']

  validates :name, :presence => true, :on => :update
  validates :dob, :presence => true, :on => :update
  validates :phone, :format => { :with => phone_regex }, :length => { :is => 10 }, :on => :update
  validates :address, :presence => true, :on => :update
  validates :state, :presence => true,:length => { :maximum => 30 }, :on => :update
  validates :city, :presence => true, :length => { :maximum => 30 }, :on => :update
  validates :country, :presence => true, :length => { :maximum => 30 }, :on => :update
end

【问题讨论】:

  • 发布您的更新操作
  • 它正在使用设计/注册#update。所以默认情况下它是由 Devise 提供的

标签: ruby-on-rails ruby-on-rails-3 devise reset-password


【解决方案1】:

实际上,问题在于您使用的是可验证的设计模块。即使在更新时,它也会对电子邮件和密码进行自动验证。更好的选择是在创建时添加您自己的电子邮件和密码验证,并在模型中进行这些更改或完全删除它。

User Model

def email_required?
  false
end

def password_changed?
  false
end

希望这会有所帮助。

【讨论】:

  • 当我更新用户配置文件时,它不会抛出“密码字段为空白”错误,但是当我更新密码时,所有带有“更新时”验证的字段都会触发“非空白”错误
  • 哦!所以你有一个用户只能更改他/她的密码的过程?
  • 是的,我为此使用了 devise registrationscontroller#edit。
  • 用户只能通过电子邮件、密码和密码确认进行注册。当时也出现了验证错误,但我已经为除密码之外的每个属性添加了“更新时”。
  • 是的,我想,不要为此使用设计编辑表单,而是创建自己的表单和控制器的操作并使用 model.update_attribute(:password, params[:password]) 来更新它。它不会运行验证
【解决方案2】:

我不确定是否有一个简单的答案。 我相信以某种方式强制用户在注册后更新这些字段(如帐户“激活”)是一个好主意。从技术上讲,如果您已经定义了这些验证,那么用户确实无效。

不过,我想您可以通过以下解决方法避免验证: 在验证中添加:unless 选项(请参阅this):

validates :name, :presence => true, :on => :update, :unless => :resetting_password?

然后定义一个resetting_password? 方法并在你这样做时让它返回true。您可以通过在设计的注册控制器中设置一个变量来做到这一点。我认为使用attr_accessor 可能就足够了。

可能有更好的解决方案,但这是我现在能想到的。

【讨论】:

  • 当我更新用户配置文件时,它不会抛出“密码字段为空白”错误,但是当我更新密码时,所有带有“更新时”验证的字段都会触发“非空白”错误
【解决方案3】:

我遇到了同样的问题。这是我找到的解决方案。

它深入研究了设计内部,因此我建议您对此进行测试。我发现我在尝试实现这一点时破坏了很多东西(包括不需要匹配的密码确认,或更改密码!)

这里有一个要点,显示了我的测试套件的 sn-p 检查密码重置:https://gist.github.com/samstickland/9744ee29d0028162a7a8

问题是设计使用验证来检查密码是否匹配,它是一个有效的密码(即不太短)并且密码令牌是有效的。这意味着一旦你停止使用有效?方法,您必须改为查找特定的错误消息。

首先,您必须在用户模型中覆盖 reset_password 方法。如果错误消息不包含任何“密码”错误,则此新方法将直接写入加密密码(作为 password= 方法的一部分创建)。

原始设计实现在这里找到:https://github.com/plataformatec/devise/blob/18a8260535e5469d05ace375b3db3bcace6755c1/lib/devise/models/recoverable.rb#L39(注意:我还没有实现 after_password_reset 因为它已被弃用)

  def reset_password(new_password, new_password_confirmation)
    self.password = new_password
    self.password_confirmation = new_password_confirmation

    if valid?
      save
    elsif errors.messages.select { |k,v| k[/password/] }.empty?
      # No password errors, so we write the password directly to the DB
      update_attribute(:encrypted_password, encrypted_password)
      true
    else
      false
    end
  end

接下来你必须实现你自己的 PasswordsController 因为更新方法也会检查错误是否为空。将其更改为仅查找密码错误。这是我的。

当您在无效模型上重置密码时,我还必须将 respond_with 更改为 redirect_to 以使重定向工作。我真的不明白为什么这是必要的。

#
# This is identical to the original devise password controller except
# that it allows resetting of passwords in invalid models (i.e.
# confirmed users without a valid profile
#

class Users::PasswordsController < Devise::PasswordsController
  # GET /resource/password/new
  # def new
  #   super
  # end

  # POST /resource/password
  # def create
  #   super
  # end

  # GET /resource/password/edit?reset_password_token=abcdef
  # def edit
  #   super
  # end

  # PUT /resource/password
  def update
    self.resource = resource_class.reset_password_by_token(resource_params)
    yield resource if block_given?

    # Was:
    #   if resource.errors.empty?
    # It's been changed to allow resetting passwords of invalid models
    if resource.errors.messages.select { |k,v| k[/password/] }.empty?
      resource.unlock_access! if unlockable?(resource)
      if Devise.sign_in_after_reset_password
        flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
        set_flash_message(:notice, flash_message) if is_flashing_format?
        sign_in(resource_name, resource)
        # Was:
        #   respond_with resource, location: after_resetting_password_path_for(resource)
        # but this didn't seem to redirect User's with invalid attributes so I've changed
        # it to a redirect
        redirect_to after_resetting_password_path_for(resource)
      else
        set_flash_message(:notice, :updated_not_active) if is_flashing_format?
        respond_with resource, location: new_session_path(resource_name)
      end
    else
      respond_with resource
    end
  end

  # protected

  # def after_resetting_password_path_for(resource)
  #   super(resource)
  # end

  # The path used after sending reset password instructions
  # def after_sending_reset_password_instructions_path_for(resource_name)
  #   super(resource_name)
  # end
end

【讨论】:

  • 你在哪里实现了自己的reset_password?直接在模型中?
【解决方案4】:

基于Sam Stickland 答案... 尽管保存update_attribute(:encrypted_password, encrypted_password) 我认为使用save(validate: false) 保存更好更明确。 您还可以避免扩展更新控制器操作来实现您的重置密码,例如

def reset_password(new_password, new_password_confirmation)
  byebug
  if new_password.present?
    self.password = new_password
    self.password_confirmation = new_password_confirmation
    if valid?
      save
    elsif errors.messages.select { |k,_v| k[/password/] }.empty?
      errors.clear
      save(validate: false)
    else
      false
    end
  else
    errors.add(:password, :blank)
    false
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 2021-11-26
    • 2012-05-23
    • 2019-09-28
    • 2013-10-14
    相关资源
    最近更新 更多