2013-04-04 84 views
1

在Rails 4.0應用程序中使用has_secure_password時,我想自動生成User的密碼(注意:這就是爲什麼沒有attr_accessor)。Rails使用has_secure_password自動生成密碼

我有一個非常簡單的模型User

class User < ActiveRecord::Base 
    has_secure_password 
    validates :email, presence: true 
end 

我不知道我怎樣才能創建一個before_save呼叫使用SecureRandom.hex(8)密碼。我試着添加before_save { self.password = SecureRandom.hex(8) }及其各種版本,但是當我試圖將它保存在Rails控制檯中時,它說password是空的。

任何幫助將不勝感激!

回答

0

嘗試使用before_validation回調代替。 before_savevalidate之後運行,因此您的記錄將始終無效。

另請考慮檢查是否已設置密碼。否則,每次更改記錄時都可以設置一個新的記錄。

查找有關ActiveRecord callback chain here的更多信息。

+0

工作出色,謝謝! – Justin 2013-04-04 22:53:28

0

回調是一個有用的解決方案,但在添加所需的複雜層次時會使測試變得困難。

另一種方法是創建一個位於「高於」用戶的類。我不會認爲這是最好的解決方案,但是我發現它是有用的。請注意,這個類從User類繼承:

# user_with_default_password.rb 
class UserWithDefaultPassword < User 
    def initialize(options = {}) 
    random_password = SecureRandom.hex(8) 

    options[:password] = random_password 

    # If creating a user with confirmation requirements 
    options[:password_confirmation] = random_password 

    # Call User.new(options) 
    super(options) 
    end 
end 

用法:

user = UserWithDefaultPassword.new() # => user.password = "ajfladfjkf..." 

這樣做的好處是,你可以測試用戶和UserWithDefaultPassword不強制回調,測試通常會減慢。

此外,如果您只需使用User.new()而不是UserWithDefaultPassword.new(),則可以使用或不使用默認密碼來創建用戶。它提供更大的靈活性和更好的測試。

更新:2014年4月21日

另外,我建議創建隨機密碼等提取碼...到一個單獨的類,您可以快速測試(不加載Rails框架)。以下是我最近爲完成這些簡單任務所做的一個課程。

#================================================== 
# Generates random/unique strings/tokens/IDs 
# See: http://ruby-doc.org/stdlib-2.0.0/libdoc/securerandom/rdoc/SecureRandom.html 
# See: http://ruby.railstutorial.org/chapters/sign-in-sign-out#sec-signin_success 
#================================================== 
class Generator 
    require "securerandom" 

    # General-purpose encryption using SHA1 instead of bcrypt; faster but LESS SECURE than bcrypt 
    # (do not use for extremely sensitive data such as passwords) 
    def self.encrypt(value) 
    if value.nil? || value.empty? 
     "" 
    else 
     Digest::SHA1.hexdigest(value.to_s) 
    end 
    end 

    # Although a UUID would work as an auto-generated password, 
    # it just seems more appropriate to make the password a random 
    # string. 
    def self.random_password 
    SecureRandom.urlsafe_base64(32) 
    end 

    # Used as a random, unique token 
    def self.uuid 
    SecureRandom.uuid 
    end 

    # Returns random number as string for admin 2-step authentication 
    def self.verification_code(length) 
    value = "" 

    if length.nil? || length.zero? 
     length = 6 
    elsif length > 20 
     length = 20 
    end 

    length.times do |num| 
     value += SecureRandom.random_number(10).to_s 
    end 

    value 
    end 
end 

用法:Generator.random_password # => "abc123..."

大好處是可以測試的隨機密碼的生成,而無需加載Rails框架,這將保存3-4秒的加載時間。這(大部分情況下)是用Rails 4.1解決的,它使用Spring來預先加載你的應用程序進行測試,但如果你不在Rails 4.1上(或者使用Spring gem),這是一個更好的解決方案。