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を行なわない
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終了。