フィルタ

フィルタは、アクションの前後で処理する仕組みだね!

before/afterは、アクションの前や後での処理ね

  • こんな感じで、アクション(controllers/ctrl_controller.rb)に、こんな感じで書くと、
     before_filter :start_logger
     …中略…
     private
     def start_logger
       logger.debug('[Start] ' + Time.now.to_s)
     end
    
  • アクション(ここだと、/ctrl/session_showね)を叩いたときに、こんなログが出る
    Started GET "/ctrl/session_show" for 127.0.0.1 at 2012-01-15 08:21:45 +0900
      Processing by CtrlController#session_show as HTML
    [Start] 2012-01-15 08:21:45 +0900
    Rendered ctrl/session_show.html.erb within layouts/application (0.0ms)
    Completed 200 OK in 47ms (Views: 46.9ms | ActiveRecord: 0.0ms)
    
    • 同様に、after_filterでもできるよー。

aroundは、アクション前後の処理をまとめて書ける!

  • こんな感じで、アクション(controllers/ctrl_controller.rb)に、こんな感じで書くと、
     around_filter :around_logger
     …中略…
     private
     def around_logger
       logger.debug('[Aroud Log Start] ' + Time.now.to_s)
       yield #ここでアクションを実行ね!
       logger.debug('[Aroud Log End] ' + Time.now.to_s)
     end
    
    • なんか、動かんなー、と思ったら、P338の表題の他、何箇所か誤字だったw(arrround→around)
  • アクション(ここだと、/ctrl/session_showね)を叩いたときに、こんなログが出る
    Started GET "/ctrl/session_show" for 127.0.0.1 at 2012-01-15 08:38:34 +0900
      Processing by CtrlController#session_show as HTML
    [Aroud Log Start] 2012-01-15 08:38:34 +0900
    Rendered ctrl/session_show.html.erb within layouts/application (0.0ms)
    [Aroud Log End] 2012-01-15 08:38:35 +0900
    Completed 200 OK in 31ms (Views: 31.2ms | ActiveRecord: 0.0ms)
    
  • 要するに、yieldでアクションを実行するのね。で、その前後の処理を書いちゃうんだね。
    • なので、ここでいろいろ条件判定して、アクションを実行させないとかもできそう!
    • ちなみに、こんな順番で、before/afterはaroundよりも外側で実行されるから、注意!
      before → around(アクション) →after
      

フィルタの適用範囲を制限するには :only/:exceptで!

  • ただ、ここにあんまり複雑な事を書くと、可読性が下がるから、変に書かないのが吉!
  • こんなで書くと、そのメソッドだけ実行される、と、
     before_filter :start_logger, :only => [ 'session_show','session_regist' ]
     after_filter :end_logger, :except => 'session_show'
    
    • :onlyは、そのメソッドだけ実行
    • :exceptは、そのメソッド以外を実行
  • で、これってアクション毎に書いてるけど、親クラス(ApplicationController)とかに書けば、アプリ全体に適用される
    • でもこのアクションでは適用したくない!、って場合は「skip_filter」とか「skip_before_filter」を使えば除外されるんだー

フィルタを使った、簡単Basic認証

  • アクションに、こんな感じ書けば、Basic認証だねー
     before_filter :auth, :only => 'session_show'
     …中略…
     private
     def auth
       name = 'abc'
       password = 'cdf'
       authenticate_or_request_with_http_basic('Railbook') do |n,p|
         name == n && password == p
       end
     end
    
    • まあ、こんなべた書きは許されんけど、単にBasic認証の例ってことで。
    • authenticate_or_request_with_http_digestを使えば、ユーザ名/パスワードをハッシュ化して受け取れるから、ちと安全?
       def auth2
         members = {'abc' => 'cdf' }
         authenticate_or_request_with_http_digest('Railbook') do |name|
           members[name] 
         end
       end
      

フィルタを使った、フォーム認証

  • まー、さすがに所詮はBasic認証なんで、普通は自前でログイン画面を作るよねw。
  • 全体の流れとしては、こんな感じだね
    • まずユーザが[/ctrl/index]にアクセスすると、before_filterで指定されたcheck_loginedが動く
    • で、check_loginedでは、セッションを見て初回なんで何にも無いので、ログインページ[/login/index]にリダイレクト
    • ログインページでは、authメソッドで、ユーザ/パスを元にチェックする
      • チェックOKなら、セッションにユーザIDを設定して、[/ctrl/index]にリダイレクト
      • チェックNGなら、refererに再度遷移先を設定して、ログインページを再表示
    • 2回目以降では、check_loginedで既にセッションがあるから、単にセッションにユーザIDを設定して終了!
  • コード的には、こんな感じ書けばいいかな?
    • まずは、元のアクションに、こんな感じでログインチェック追加
       before_filter :check_logined, :only => 'index'
       …中略…
       def index
         render :text => 'ユーザ=[' + @usr + ']で、indexが表示できたよ!'
       end
      
       private
       def check_logined
         members = {'abc' => 'cdf' } # 当然ほんとは、Digest::SHA1.hexdigestとかで暗号化は必須ね!
         if session[:usr] && members[session[:usr]] # セッションがあって、かつmembersにデータがあれば、OK
           @usr = session[:usr]
         else
           reset_session unless members[session[:usr]] # membersに見つからないなら、セッションをリセット
           flash[:referer] = request.fullpath # ログインページから元々のURLへのリダイレクト用にフラッシュで渡す
           redirect_to :controller => 'login', :action => 'index'
         end
       end
      
      • うーん、ユーザIDを変なのにしたら、セッションが消えるはずなんだが…。どうして、session_idが同じなんだ?reset_session は_session_idを取り直さないのかな?
      • んー、ログアウト時は_session_idが変わってるし、違うなー。なんか間違ってる?
      • あー、判った。flashを使ってるから、セッションIDはクリアされないだけなんだw
      • あと、check_loginedでのreset_session処理は、「セッションがが無い場合」なので、初回表示時にセッションをクリアするためねー。理解!
    • で、今度はログイン画面のほうね!
      • まずは、ビュー(views/login/index.html.erb)はこんな感じ
        <p style="color: Red"><%= @error %></p>
        <%= form_tag :action => 'auth' do %>
          <div class="field">
            <label>ユーザ名:<%= text_field_tag(:username) %></label>
          </div>
          <div class="field">
            <label>パスワード:<%= password_field_tag(:password) %></label>
          </div>
          <%= hidden_field_tag :referer, flash[:referer] %>
          <%= submit_tag 'ログイン' %>
        <% end %>
        
      • んでもって、コントローラ(controllers/login_controller.rb)は、こんな感じ
        class LoginController < ApplicationController
         def auth
           members = {'abc' => 'cdf' } # 当然ほんとは、Digest::SHA1.hexdigestとかで暗号化は必須ね!
           if members[params[:username]] && params[:password] == members[params[:username]]
             session[:usr] = params[:username]
             redirect_to params[:referer]
           else
             flash.now[:referer] = params[:referer] # NG時のログインページ用に、遷移先をflash.nowで再設定
             @error = 'ユーザ名/パスワードが間違ってる!!'
             render 'index'
           end
         end
        end
        
    • これで、[/ctrl/index]を叩けば、初回はログイン画面[/ctrl/login]が出て、ログインに成功すれば[/ctrl/index]にリダイレクトされる、と
  • あとは、ログアウトを作ればいいよね
    • といっても、こんな感じでreset_sessionすればOK!
       def index
         render :text => 'ユーザ=[' + @usr + ']で、indexが表示できたよ!<br>ログアウトは<a href="/ctrl/logout">こちら</a>'
       end
       def logout
         reset_session
         redirect_to '/'
       end
      

-
最終更新:2012年01月20日 07:41