AWDwR "Chapter16 Action Controller and Rails" つづきのつづき

まだまだActionController。ちょっと飽きた… 嘘:-)。

Filters and Verification

フィルタを使うとアクションの前や後などで処理を行なうことができるのよ。before, after, aroundの3種類があるのよ。

まずはbeforeフィルタとafterフィルタ。コントローラ内のメソッドをフィルタに指定する場合はこんな感じ。

class AdminController < ApplicationController
  before_filter :authorize
  
  def authorize
    ...
  end
end

ブロックやクラスもフィルタに指定できて、クラスを指定する場合はこんな感じ。

class AuditFilter
  def self.filter(controller) # filterというクラスメソッドを定義しておく
    ...
  end
end

class SomeController < ApplicationController
  after_filter AuditFilter
end

フィルタは基本的に全てのアクションに適用されるんだけど:onlyオプションや:exceptオプションで適用するアクション、適用しないアクションを指定できる。またbefore_filter, after_filterはフィルタチェーンの最後にフィルタを追加するんだけど、prepend_before_filter, prepend_after_filterはフィルタチェーンの先頭にフィルタを追加する。

で、aroundフィルタ。これはアクションの前後に適用させるフィルタ。beforeメソッド、afterメソッドを定義したフィルタクラスを定義しておく。

class TimingFilter
  def before(controller)
    ...
  end

  def after(controller)
    ...
  end
end

class SomeController < ApplicationController
  around_filter TimingFilter.new

  ...
end

aroundフィルタには:onlyオプション、:exceptオプションはない。また適用順序はbeforeメソッドはbeforeフィルタチェーンの最後に追加され、afterメソッドはafterフィルタチェーンの先頭に追加される。


それからアクションを実行する前の事前条件をチェックするためにverifyという仕組みがあって、以下のような感じで使う。

class BlogController < ApplicationController
  verify :only => :post_comment,
         :session => :user_id,
         :add_flash => {:note => "Login Failed"},
         :redirect_to => :index
end

verifyで指定できるパラメタは以下のとおり。

  • :only 指定したアクションでverifyを行なう
  • :except 指定したアクションにはverifyを行なわない
  • :flash flashに指定されたキーが含まれていること
  • :method リクエストメソッドが指定されたもの(:get,:post,:head,:delete)であること
  • :params リクエストパラメタに指定されたキーが含まれていること
  • :session セッションに指定されたキーが含まれていること
  • :add_flash flashにメッセージを追加する
  • :redirect_to 指定されたアクションにリダイレクトする

Caching, Part One

ページキャッシング、アクションキャッシング、フラグメントキャッシングの3種類のキャッシング機構を持っていて、ページキャッシングは最も単純で一度アクセスされたページをキャッシングするもの、アクションキャッシングはbeforeフィルタだけ実行され、それ以降はアクションは実行せずキャッシュが使われるもの、フラグメントキャッシングは…Part Twoで。

class ContentController < ApplicationController
  caches_page :public_content
  caches_action :premium_content
end

デフォルトではキャッシングはプロダクション環境でのみ有効となっていて、キャッシングをon/offするには以下のようにする。

ActionController::Base.perform_caching = true | false


キャッシュを明示的にエクスパイアするにはexpire_page, expire_actionを使う。

expire_page :action => "public_content"
expire_action :action => "premium_content", id => article

またモデルを監視し変更があった場合にキャッシュをエクスパイアするsweeperという方法もある。

class ArticleSweeper < ActionController::Caching::Sweeper
  observe Article

  def after_create(article)
    expire_public_page
  end

  def after_update(article)
    expire_article_page(article.id)
  end

  def after_destroy(article)
    expire_public_page
    expire_article_page(article.id)
  end

  private

  def expire_public_page
    ...
  end

  def expire_article_page(article_id)
    ...
  end
end

sweeperはコントローラの中に定義することもできる。

class ContentController < ApplicationController
  cache_sweeper :article_sweeper,
                :only => [:create_article, :update_article, :delete_article]

一定時間でキャッシュをエクスパイアしたい場合、キャッシュファイルはpublicディレクトリ以下にhtmlファイルとしてできるので、それをバックグラウンドプロセスかなんかで削除してね、ってやってくれないのか…。それからアクションキャッシングはこの方法ではエクスパイアできないので注意。

The Problem with GET Request

カートに商品を追加したり、ユーザを削除したりといった状態を変化させるアクションをGETリクエストでできるようにしておくと、検索エンジンのスパイダーやブラウザの先読みキャッシュ、リロードなんかで実行されちゃうから注意しましょうね。そういうのはPOSTメソッドにしておくこと。つまり

"Put All Destructive Actions Behind a POST Request"

というわけでActionController終了。