今更ですが再確認を (2)

昨日の続きで以下ドキュメントの 8 章以降再確認。

しかし今年の始め頃に 3.2 な英語版を辛苦して読んでいたのですが、コミュニティの力って凄いですね。日頃はドキュメントは英語で読むべき、とか言ってますが、やっぱ若い方々に紹介する時は日本語になってた方がハードルは下がります。
という訳で (?) 早速確認着手。

8 章

signin および signout の昨日実装するのですが、これに伴い signin/signout の状態と signin しているユーザ id に応じた動作、を実現できるとのこと。

  • ヘッダに signin/signout のリンクとプロファイルへのリンクを表示
  • 10 章にて signin しているユーザ id を使って関連しているマイクロポストを表示
  • 11 章ではフォローしているユーザのフィードを表示

あるいは signin によるセキュリティモデルの実装、という部分についても説明があります。

  • signin しているユーザ id に基づいた特定のページへのアクセス制限
  • ユーザ情報編集ページへのアクセスの制限
  • 管理者ユーザに特別な権限を付与 (ユーザ削除など)

きちんと章のアタマでこうなります、というあたりの情報がある、というのは大切ですね。
あと、昨日のエントリで 8.1 あたりはざっくり列挙できているので、ここでは 8.2 にフォーカスをあてて色々確認してみたいと思います。
まず、Sessions コントローラの create アクションから作成着手。User モデルを使って認証に成功したら sign_in というメソドを使って signin させてリダイレクト、とあります。

  def create 
    user = User.find_by_email(params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      sign_in user
      redirect_to user

sign_in というメソドは未定義なのでまだ動かないとのこと。8.2.1 から実装に着手なのかどうか。サインインモデルの実装としては

  • サインイン状態を「永続化」して
  • ユーザが明示的にサインアウトしたときにのみセッションを削除

とのこと。ああ、確かにサインインの状態についてはコントローラからもビューからも使えるようになってて欲しいですね。これを SessionHelper というモジュールを使って実装する模様です。
む、ヘルパーはビューではデフォで使えるけど、コントローラではそうではなくて使いたいのであれば明示的に include せよ、というあたりもポイント高いですね。

session
  • HTTP はステイトレス
    • ステイトレス、なフォロー必要か
  • 状態が保存されない
  • サインインの状態を保持する方法のひとつとして、特殊な session 関数を使って remember token を保持
  • session オブジェクトは cookie を使っているとのこと
    • cookie はブラウザを閉じると無効になる

今回の実装ではブラウザを閉じた後にもサインイン状態を保持する形を採用している模様。なので User モデルに remember_token 属性を追加、なのか。む、もしかして migration でテーブルに属性追加、はここで始めて出てくるのかな。
あと、remember_token をどこから取得するか、なあたりは初心者向けにはスルー気味で良いのかどうなのか。

self キーワード

これ、model 上ではカラム追加されていない事になっているので self 付けてね、って事になるのかな。

まだ続く

SessionsHelper#signin ですが、cookie に remember_token を設定して云々してます。

module SessionsHelper

  def sign_in(user)
    cookies.permanent[:remember_token] = user.remember_token
    self.current_user = user
  end
end

以下な注意が列挙されてます。

  • current_user は属性であることを明示する必要あり
  • setter なメソドを定義する必要があること

そして何故に getter が

  def current_user
    @current_user     # 役に立たない。この行は使用しないこと。
  end

では駄目なのか、もフォロー必要ですね。ええと、SessionHelper なオブジェクトはページ毎に異なる、という理解で良いのかどうか。別途時間がある時に確認入れます。
8.2 の残りもうちょいですが、ちょっと時間切れ。別途確認入れ次第エントリ追記します。

追記

随分前段から整理が必要な事に気づくなど。ちょっと以下にポイントを列挙。

  • サインイン、サインアウトの要素は Sessions コントローラの特定の REST アクションがそれぞれ対応とのこと。
  • サインインのフォームは new アクションで処理 (表示)
  • 実際のサインインの処理は create アクションに POST リクエストが送信されたときに処理
  • サインアウトは destroy アクションに DELETE リクエストが送信されたときに処理

config/routes.rb に以下な記述を追加するだけで、表 8.1 な形になるのか。

  resources :sessions, only: [:new, :create, :destroy]

  match '/signin',  to: 'sessions#new'
  match '/signout', to: 'sessions#destroy', via: :delete

で、create なアクションに認証処理をごりごり書いてますね。つうか Session コントローラって特別な事してる (してますが) のかと思ったら signin/signout なんですね。ふむふむ。
あるいは 8.2.1 節にて ApplicationController なクラスで SessionHelper を include している記述が出てきてます。

class ApplicationController < ActionController::Base
  protect_from_forgery
  include SessionHelper

これ、Controller なクラス定義の中に SessionHelper な定義を include する、という事なはずなのですが、Rails って例えば signin なリクエストを受けると SessionController なオブジェクトを生成して面倒を見させる、という理解で良いのかな。
ということは SessionHelper は ApplicationController の属性になるので、Controller 毎に current_user な属性をセットし直す必要があるのかどうか。
なので、以下な記述が必要、って理解で良いのかな。

@current_user ||= User.find_by_remember_token(cookies[:remember_token])

ここが理解できてれば以降は楽に読みすすめることができるのかどうか。