#session
##HTTPはステートレスなプロトコル
HTTPのリクエスト1つ1つは、それより前のリクエストの情報をまったく利用できない、独立したトランザクションとして扱われます。HTTPは言ってみれば、リクエストが終わると何もかも忘れて次回最初からやり直す健忘症的なプロトコルであり、過去を捨てた旅から旅の流れ者的なプロトコルです
そのため、HTTPにはユーザーIDを保存しておく手段がない
→sessionと呼ばれる半永続的な接続は、HTTPとは階層が異なるために、独立して扱うことができる。
→Railsではcookiesと言われるユーザーのブラウザに保存される小さなテキストデータを利用する
###ルーティングの確認
$ rails routes
で現在のルーティングを確認
##sessonではエラーメッセージは手動
sessionはactiverocordオブジェクトを扱っていないので、自分でエラーメッセージを設定する必要がある
→フラッシュメッセージでエラーメッセージを表示
##sessionでのform_forの使い方
form_for(@user)
のようなコードはuserモデルが存在するために、railsが自動で「フォームのactionは/usersというURLへのPOSTである」と解釈してくれるが、sessionの場合はsessionモデルが存在しないから、この方法は使えない
→セッションの場合はリソースの名前とそれに対応するURLを{ session: { password: "foobar", email: "user@example.com" } }的に指定する必要がある
form_for(:session, url: login_path)
ユーザーから送られたログイン情報は
params = { session: { password: "foobar", email: "user@example.com" } }
というハッシュに保存されている。
#フラッシュによるエラーメッセージの表示
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
# ユーザーログイン後にユーザー情報のページにリダイレクトする
else
flash[:danger] = 'Invalid email/password combination' # 本当は正しくない
render 'new'
end
end
redirect_toではなくrenderを使ってレンダリングしても、フラッシュメッセージは残り続けてしまう
→flash.now[:danger]
とすることで、メッセージはその後リクエストが発生したときに消滅する
##log_inメソッド
###sessionメソッド
Railsに事前定義済みのメソッド
session[:キー] = 値
でセッションに情報を保存できる。キーを使って値を取りだせる
session[:user_id] = user.id
上のコードを実行すると、ユーザーのブラウザ内の一時cookiesに暗号化済みのユーザーIDが自動で作成されます。この後のページで、session[:user_id]を使ってユーザーIDを元通りに取り出すことができます。一方、cookiesメソッド (9.1) とは対照的に、sessionメソッドで作成された一時cookiesは、ブラウザを閉じた瞬間に有効期限が終了します。
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
ログイン成功時の一連の流れ
①find_byメソッドを使って、ログインフォームに入力された情報をparamsハッシュから取り出して検索し、user変数に格納する
②ログインフォームに入力されたユーザーの存在性とauthenticateメソッドでパスワードをハッシュ化して、事前にハッシュ化して保存されていたパスワードと認証する。
③log_in ヘルパーを用いて、ユーザーのidをsession[:user_id]に保存する。
##現在のユーザー
current_userメソッドを定義することで、ログイン中のユーザーの情報を取り出しやすくする
def current_user
if session[:user_id]
User.find_by(id: session[:user_id])
end
end
##テストユーザーの作成
テストユーザーのpassword_digest属性を設定するために、暗号化のメソッドをクラスメソッドとして、ユーザーモデルに定義する。
BCrypt::Password.create(string, cost: cost)
でパスワードが生成されている
上のstringはハッシュ化する文字列、costはコストパラメータと呼ばれる値です。コストパラメータでは、ハッシュを算出するための計算コストを指定します。コストパラメータの値を高くすれば、ハッシュからオリジナルのパスワードを計算で推測することが困難になりますので、本番環境ではセキュリティ上重要です。しかしテスト中はコストを高くする意味はないので、digestメソッドの計算はなるべく軽くしておきたいです。
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
コストパラメータをテスト中は最小にし、本番環境ではしっかりと計算する方法
##ログアウト
ログアウトの処理では、リスト 8.14のlog_inメソッドの実行結果を取り消します。つまり、セッションからユーザーIDを削除します15。そのためには、次のようにdeleteメソッドを実行します。
session.delete(:user_id)