Railsでログイン処理の実装

ログイン処理を行う場合、すべての画面でログイン状態かどうかを判定してログイン状態出ない場合はログイン画面へ遷移するという処理が必要になります。すべての画面に対応するコントローラでそのような処理を行う場合、たいていのフレームワークではアプリケーション共通の処理を定義することが可能となっています。

Railsも同様で、Applicationコントローラ(Application.rb)に該当する処理を定義することができます。

[sourcecode language="ruby"]

coding:utf-8

class ApplicationController < ActionController::Base

# ロケールの設定用フィルタ before_filter :detect_local

# ログイン認証用のフィルタ before_filter :check_logined

protect_from_forgery

private def detect_local I18n.locale = request.headers["Accept-Language"].scan(/^[a-z]{2}/).first end

# 認証状況を確認するフィルタの定義 def check_logined if session[:user_id] begin @user = UserInfo.find_all_by_user_id(session[:user_id]) rescue ActiveRecord::RecordNotFound logger.error "セッションの情報(" + session[:user_id] + ")は user_infos には存在しません。" reset_session end end

unless @user
  flash[:referer] = request.fullpath
  redirect_to :controller =&gt; 'login', :action =&gt; 'index'
end

end end [/sourcecode]

この場合、check_loginedというメソッドを before_filter :check_logined で使用するように定義しています。before_filter はコントローラで定義された処理の前に行う処理を定義するフィルタです。

そもそも、Scaffoldingで自動生成されるコントローラはActionControllerを継承しています。つまり、ApplicationControllerで定義したフィルタはサブクラスであるコントローラが処理を行う前に実行されることになります。

ということは、ログイン画面に対応するコントローラでもログイン状態をチェックするフィルタが実行され、ログインしていないためログイン画面へ遷移するという循環参照が発生してしまいます。

そこでログイン画面だけはApplicationControllerで定義されたフィルタを使用しないようにする必要があります。

[sourcecode language="ruby"]

循環しないようにログインフィルタをスキップする

skip_before_filter :check_logined

[/sourcecode]

sikip_before_filter :check_logined を定義することでApplicationController などスーパークラスで定義されたフィルタをスキップすることができます。

私の家計簿作成も終盤になってきました。当初Railsは「設定より規約」でもわかるとおりかなり融通が利かないフレームワークなのかと思っていましたが、少なくとも今の私にはとても自由度が高いフレームワークだと感じられます。