tnkzw.sake

HomeSeriesTagsAbout

Rails Tutorialで学べることメモ-第8章-

Series
Railsチュートリアル

Rails Tutorial を改めてしっかりやり直してのメモ第 8 章編

https://railstutorial.jp/chapters/basic_login?version=7.0https://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で扱うリソースに相当するものを指定する。

こうすると例の場合/loginscope[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 に保存することである。

クッキーはサーバとブラウザ間の状態を保持する通信プロトコルの一種と言われることもあるようだが、状態に関連した値のキーバリューテキストだと考えておけば十分。

findfind_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.ymlsakeで定義したユーザー情報にアクセスできる。

safe navigation 演算子(ぼっち演算子)

&.で表現される演算子で、object&.fooは object がnilでないときにメソッドfooを呼び出す。

細かな知識

  • :see_otherは HTTP ステータス 302。DELETE後のリダイレクトなどで利用

まとめ

ログインの基本的な仕組み(ログイン状態を保持し、ブラウザが閉じたらこれを破棄する)を学ぶ章だった。
セッション、クッキーのようなステートレスな HTTP で通信を行うインターネットの世界で状態を持つの仕組みから、メモ化、||=演算子、ボッチ演算子&.など実際の現場でもよく見るテクニックも豊富に紹介されており、数年前の自分に欲しい情報がギュッとまとまっている印象を受けた。