Rails Tutorialで学べることメモ-第8章-
Rails Tutorial を改めてしっかりやり直してのメモ第 8 章編
https://railstutorial.jp/chapters/basic_login?version=7.0
便利なコマンド・機能
rails routes
名前付きルートの命名も含めて、全ルーティングを一覧できるコマンド。
/rails/info/routes
にアクセスしても同じ情報を見ることができる。
form_with(url: login_path, scope: :session)
ActiveRecord のモデルに関して、form_with(@user)
のように書けば、自動的に/user
へのPOST
だと判断されたが、そうでない場合はurl
で送信パス、scope
で扱うリソースに相当するものを指定する。
こうすると例の場合/login
にscope[email]
のようなハッシュを POST するフォームが作成される。
flash.now
flash
のメッセージはリダイレクトなど別のアクションが発生することで中身が消滅する。(次のアクション発生時には残っているが、そのアクションが終わったら消えるイメージ)
つまり、render
メソッドなどでログイン失敗時に同じページを再レンダリングしてもflash
は消えず、次の無関係なページでflash
の内容が表示された後、さらに移動したらようやく消える。
flash.now
とすれば、現在のアクション処理後に中身が消えるため、現在のページだけでメッセージを出したい場合はこちらを利用する。
session
Rails で定義済みのメソッド。
次のようなコードを実行すると、情報を入れた一時 cookies が自動で生成される。
session[:user_id] = user.id
この cookies は自動で暗号化されるため、仮に攻撃者に値が漏れても cookies の有効期限内に復号されなければ、不正アクセスは発生しない。
しかし、逆に言えば有効期限のない cookies(ログイン状態を永続化する)の値が漏れたら大事になりうる。
また、発行されるsession_id
が攻撃者の準備した値にならないようにする(セッション固定攻撃の防止)工夫も必要になる。これはreset_session
メソッドを実行してセッション id を新しいものに切り替える処理をすることで達成できる。
知識
セッション
HTTP の重要な特徴として、ステートレス性が挙げられる。
State(状態)less(なし)の名の通り、HTTP に則った応答は状態を持たず、全てが独立している。
状態がないを言い換えると、文脈がないという表現もできる。個人的にはこの言い換えもあった方がわかりやすい。
ステートレスではあるが、Web サービスではログインのように状態を扱いたいこともあるので、HTTP 通信とは別で状態を保持できる仕組みが必要になる。
一つがセッションと呼ばれる概念であり、Rails ではCookieを利用した実装が一般的。
Rails における実装のアイデア
セッションを RESTful なリソースとしてとらえる。
つまり、new
, create
, destroy
などでセッションを生成し、破棄すると考える。
その他のリソースとの違いは、データを DB ではなく cookie に保存することである。
Cookie
クッキーはサーバとブラウザ間の状態を保持する通信プロトコルの一種と言われることもあるようだが、状態に関連した値のキーバリューテキストだと考えておけば十分。
find
とfind_by
find
メソッドはレコードが見つからないと例外を発生させる。
プロフィールページのように、ユーザーがいない場合は例外を発生させた方が良い場合はこの挙動が適切。
しかしログイン中のユーザーを探す場合、ログインしていない状態も Web ページでは取り扱うので例外が発生すると困る。
この場合はfind_by
メソッドを用いれば、見つからない場合はnil
を返してくれるので良い。
メモ化(memoization)
DB 問い合わせなどのコストがかかる処理結果をインスタンス変数に保存しておき、以降はその変数を参照して結果の再利用を行うことをメモ化という。
memoization は r が抜けているわけではなく、memorization をもじった造語らしい。
or equals
メモ化は例えば以下のような記述がある。
@current_user ||= User.find_by(id: session[:user_id])
この||=
は@current_user = @current_user || User.find_by(id: session[:user_id])
を省略した記述である。
他の言語にもある、次のような記述と同じと言えばスッと理解できる。
let score = 100;
if (condition) {
score += 100; // score = score + 100
}
このような論理演算子を左から評価して、評価を止めても以降の評価に影響しない箇所で評価を中断する評価法を短絡評価(short-circuit evaluation)と呼ぶらしい。
Importmap
これまで Rails は JavaScript アセットを導入する手法が混乱していたが、Importmap と呼ばれる手法で標準化されたらしい。
importmap-rails
という gem を導入し、js を設置したら Importmap に読ませるための設定を書けば良いというイメージ。
fixture
minitest 実行の際に仮のデータを定義できる仕組み。
YAML で定義し、値として ERB もかける。
user = users(:sake)
とすると、environments/sample_app/test/fixtures/users.yml
のsake
で定義したユーザー情報にアクセスできる。
safe navigation 演算子(ぼっち演算子)
&.
で表現される演算子で、object&.foo
は object がnil
でないときにメソッドfoo
を呼び出す。
細かな知識
:see_other
は HTTP ステータス 302。DELETE
後のリダイレクトなどで利用
まとめ
ログインの基本的な仕組み(ログイン状態を保持し、ブラウザが閉じたらこれを破棄する)を学ぶ章だった。
セッション、クッキーのようなステートレスな HTTP で通信を行うインターネットの世界で状態を持つの仕組みから、メモ化、||=
演算子、ボッチ演算子&.
など実際の現場でもよく見るテクニックも豊富に紹介されており、数年前の自分に欲しい情報がギュッとまとまっている印象を受けた。