如何跳过has_secure_password的验证

23

我的应用程序只允许管理员创建新的用户记录。 用户会收到一封带有激活链接的电子邮件,在那里他们可以设置密码。

我想使用has_secure_password方法(railscast):

class User < ActiveRecord::Base
  has_secure_password
  ...
end

功能很好,但它自动验证密码摘要的存在...所以当管理员创建记录时,验证失败。有没有一种方法可以跳过仅自动添加的password_digest验证,而不跳过我添加的其他验证?

4个回答

33
自从Rails 4.X版本,has_secure_password有一个选项::validations。如果你将它设置为false,它将不运行验证。
这个宝石的3.X版本不支持此参数。但是,您可以从latest 4.0.XRC code回溯activemodel/lib/active_model/secure_password.rb,该文件支持此参数。
因此,您的代码将如下所示:
class User < ActiveRecord::Base
  has_secure_password :validations => false
  ...
end

3
在可选的情况下,是否可以使用:validations进行验证?我的意思是,如果有密码值,则应该进行验证,否则就跳过。 - Mohammad

14

我决定自己进行自定义认证。以下解决方案将验证密码,但仅在设置密码时才进行验证。这使管理员可以创建用户而无需添加密码。

class User < ActiveRecord::Base
  include BCrypt

  attr_accessor :password, :password_confirmation

  validates :password, length: (6..32), confirmation: true, if: :setting_password?

  def password=(password)
    @password = password
    self.password_hash = Password.create(password)
  end

  def authenticate(password)
    password.present? && password_hash.present? && Password.new(password_hash) == password
  end

private

  def setting_password?
    password || password_confirmation
  end

end
如果有人发布了一个回答,允许我继续使用has_secure_password方法,那么我会接受它。

2
嘿,只是想说谢谢你提供这个片段,它完美地满足了我在社交认证方面的需求。 - Matt Ramirez
太有灵感了!我现在正在使用这个稍微变通的方法来支持多个登录,允许普通的电子邮件/密码登录以及无需密码的Facebook身份验证。非常牛逼,我说! - FireDragon
您需要按照以下方式更改您的魔法代码,否则,即使密码为空,它也会生成password_digest: def password=(password) @password = password if password.present? self.password_digest = Password.create(password) end end - Mohammad

1

无法跳过验证,但编写自己的方法版本以允许传递参数来确定是否验证密码摘要字段将非常容易。

只需像SecurePassword module中那样扩展ActiveModel(通过ActiveSupport::Concern),然后添加自己的安全密码方法。

例如:

module ActiveModel
  module MySecurePassword
    extend ActiveSupport::Concern

    module ClassMethods
      def my_has_secure_password(validate_password_digest=true)
        # you custom logic
      end
    end
  end
end

可以这样做。但感觉有点不对劲。我希望能找到更优雅的解决方案。 - tybro0103

0
借鉴Journeyer和Tybro的答案,我想看看是否可以添加一个返回true或false的私有方法到验证哈希表中。它可以工作,并且我已将其用于不同的用例,但在这个情况下,它应该类似于这样。

  class User < ActiveRecord::Base
    has_secure_password validations: !:setting_password

   #If setting_password is true then this will be the same as 
   validations: false
   ..... 
   private

   def setting_password?
    #Some logic that determines if a user is setting a password and resolves 
    to true or false
    password || password_confirmation
   end
   ...
  end


我尝试过,但我的代码从未运行实际的方法。如果我在其中记录任何内容,它从未显示出来。 !:setting_password 总是返回 false,没有 ! 则总是返回 true。 你找到解决办法了吗? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接