railsでアプリケーションを作成しています。
テストアカウントでのログイン機能を実装したときにエラーが発生したため、自分が行った解決方法を記録として残しておきます。
開発環境
Ruby 2.6.5
Rails 6.0.3.3
実装内容
以下のコードでテストログイン機能の実装を行いました。
コントローラー
class Users::SessionsController < Devise::SessionsController
# ゲストユーザーとしてログイン
def new_guest
user = User.find_or_create_by!(nickname: 'ゲストユーザー', email: 'user@example.com') do |user|
user.password = SecureRandom.alphanumeric
end
sign_in user
redirect_to root_path, notice: 'ゲストユーザーとしてログインしました。'
end
end
モデル
#半角英数字のみを許可するバリデーションを設定
PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?[\d])[a-z\d]+\z/i.freeze
validates_format_of :password, with: PASSWORD_REGEX, on: :create, message: 'には半角英字と半角数字の両方を含めて設定してください'
開発環境でもエラーが発生することなく、テストも通ったため、本番環境にデプロイをしたところ「Sorry, something went wrong.」が表示されてしまいました。
原因
SecureRandom.alphanumeric
で英字のみのパスワードが発行されていたため。
そもそもSecureRandomはレファレンスでは以下のように説明がされています。
安全な乱数発生器のためのインターフェースを提供するモジュールです。 HTTP のセッションキーなどに適しています。
そしてalphanumeric
はSecureRandomモジュールのメソッドの一種であり、ランダムな英数字を生成してくれます。しかし必ずしも英数字混合で生成されるわけではありません。
pry(main)> SecureRandom.alphanumeric
=> "NNCMHbfUbHRQmbwW"
確率は高くはないですが、上記のように英字のみのパスワードが生成されてしまうことがあります。
解決策
class Users::SessionsController < Devise::SessionsController
# ゲストユーザーとしてログイン
def new_guest
user = User.find_or_create_by!(nickname: 'ゲストユーザー', email: 'user@example.com') do |user|
user.password = SecureRandom.alphanumeric(10) + [*'a'..'z'].sample(1).join + [*'0'..'9'].sample(1).join
end
sign_in user
redirect_to root_path, notice: 'ゲストユーザーとしてログインしました。'
end
end
力技になってしまいましたが、[*'a'..'z'].sample(1).join + [*'0'..'9'].sample(1).join
とすることでパスワードの最後に必ず英字+数字の2文字が入るようにして英字のみor数字のみのパスワードが生成されないようにしました。