古いデータベースから大量のユーザーを移行しようとしています。これを行うには、activerecord-importを使用し、すべてのユーザーデータをDBに直接保存しようとしています(ユーザーモデルをバイパスします)。
私の問題:古いユーザーのプレーンテキストパスワードを取得して暗号化し、DBに直接保存する必要があります。 generate Deviseを使用してパスワードを作成する方法は知っていますが、データベースに直接保存できるハッシュされたパスワードを取得する方法があるかどうか疑問に思っています。
やりたいこと:
new_hashed_password = Devise.awesome_encrypting_method(old_user.password)
次に、モデルを経由せずに「new_hashed_password」を直接DBに保存します。私はDeviseを掘り下げて、これを見つけました:
def password_digest(password)
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
end
@@ stretchesのデフォルトは10(lib/devise.rb:71)であり、イニシャライザーによってオーバーライドされません
@@ pepperのデフォルトはnil(lib/devise.rb:148)であり、イニシャライザーによってオーバーライドされません
Password_digest()を手動で再作成できると思ったが、パスワードとストレッチを設定しても、結果のハッシュは毎回異なるため、Bcryptの基本的な何かが欠けていると思う。
何か案は?ご協力いただきありがとうございます!
良いニュースと悪いニュース。
以下は、ユーザーのパスワードを手動で作成するために機能します。
pepper = nil
cost = 10
encrypted_password = ::BCrypt::Password.create("#{password}#{pepper}", :cost => cost).to_s
コショウとコストは、devise initializerで見つけることができます。この方法は、Deviseの「valid_password?」を使用して確認されました方法。
「User.new(password:password).encrypted_password」を避けようとしたすべての理由は、速度のためでした。とても遅いです。インポートタスクの他のすべての部分で、これを意図的に回避しました。
しかし、結局のところ、ここでの主なコストはUserオブジェクトのインスタンス化ではなく、BCrypt自体です。意図的に低速に設計されているため、BCryptを直接使用する場合、顕著な速度向上はほとんどありません。
私の最後の答え:それを吸い上げ、レーキスクリプトを実行し、飲み物を探しに行きます。
次のようにする必要があります。
password = 'the secret password'
new_hashed_password = User.new(:password => password).encrypted_password
これは、コードからパスワードが生成される方法を抽象化してBCryptを直接使用するよりもはるかに優れており、理解しやすく、またdeviseが暗号化パスワードを作成する方法の変更に影響されません。あなたのコードはそうすべきではなく、それについて何かを知る理由はありません。
上記の他の答えはどれも私には役に立たなかったので、ここに私がやったことです:
user.valid_password?(plain_password)
別の方法は次のとおりです。User.new.send(:password_digest, 'xxx')
「users」テーブルと「password」列を持つmysqlデータベースと、考案するために接続される「user」というActiveRecordモデルクラスがあると仮定します。
アプリでActiveRecordモデルクラスを作成しますapp/models/old_user.rb
OldUser < ActiveRecord::Base
set_table :users
establish_connection :database => "old_database", :user => "old user", :adapter => "mysql"
end
次に、rakeタスクを作成します:app/lib/tasks/migrate_users.rake
task :migrate_users => :environment do
OldUser.find_each do |old_user|
u = User.new(:email => old_user.email, :password => old_user.password, :password_confirmation => old_user.password);
#if your using confirmation
u.skip_confirmation!
u.save!
end
end
必要に応じて変更します(アプリ固有のユーザー属性を保存していることを確認してください)
Then$ rake migrate_users