8.1 セッション
HTTPはステートレス (Stateless) なプロトコルです。文字通り「状態 (state)」が「ない (less)」ので、HTTPのリクエスト1つ1つは、それより前のリクエストの情報をまったく利用できない、独立したトランザクションとして扱われます。
ユーザーログインの必要なWebアプリケーションでは、セッション (Session) と呼ばれる半永続的な接続をコンピュータ間 (ユーザーのパソコンのWebブラウザとRailsサーバーなど) に別途設定します。
Railsでセッションを実装する方法として最も一般的なのは、cookiesを使う方法です。cookiesとは、ユーザーのブラウザに保存される小さなテキストデータです。
8.1.1 Sessionsコントローラ
Sessionsコントローラを生成する
rails generate controller Sessions new
config/routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users
end
#セッションルールによって提供されるルーティング
HTTPリクエスト URL 名前付きルート アクション名 用途
GET /login login_path new 新しいセッションのページ (ログイン)
POST /login login_path create 新しいセッションの作成 (ログイン)
DELETE /logout logout_path destroy セッションの削除 (ログアウト)
演習
1:GET login_pathとPOST login_pathとの違いを説明できますか?
少し考えてみましょう。
get '/login', to: 'sessions#new' post '/login', to: 'sessions#create'
GET login_path: “/login”へアクセスされた際に”sessions#new”アクションを実行
POST login_path: “sessions#create”アクションの情報を”/login”へ送信。
Getは/loginのリクエストが来た際にsessionsコントローラのnewアクションをするという意味でPostはsessionsコントローラのcreateアクションを/loginに送信する
2:ターミナルのパイプ機能を使ってrails routesの実行結果とgrepコマンドを繋ぐことで、Usersリソースに関するルーティングだけを表示させることができます。
同様にして、Sessionsリソースに関する結果だけを表示させてみましょう。
現在、いくつのSessionsリソースがあるでしょうか?
rails routes | grep users#
rails routes | grep sessions# 3つ
form_for(@user)
Railsでは上のように書くだけで、
「フォームのactionは/usersというURLへのPOSTである」と自動的に判定しますが、
セッションの場合はリソースの名前とそれに対応するURLを具体的に指定する必要があります。
form_for(:session, url: login_path)
8.1.2 ログインフォーム
演習
リスト 8.4で定義したフォームで送信すると、Sessionsコントローラのcreateアクションに到達します。Railsはこれをどうやって実現しているでしょうか?
ヒント:表 8.1とリスト 8.5の1行目に注目してください。
action=”/login” method=”post”から/loginにPostする場合
sessionsコントローラのcreateアクションが実行されるため
8.1.3 ユーザーの検索と認証
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
# ユーザーログイン後にユーザー情報のページにリダイレクトする
else
# エラーメッセージを作成する
render 'new'
end
end
def destroy
end
end
User Password a && b
存在しない 何でもよい (nil && [オブジェクト]) == false
有効なユーザー 誤ったパスワード (true && false) == false
有効なユーザー 正しいパスワード (true && true) == true