使用過濾器


控制器的動作在執行之前、後,若有些共同要執行的動作,可以使用before_filter、after_filter和around_filter來定義,例如若想要檢查使用者是否登入,可以如下:

class ApplicationController < ActionController::Base
    before_filter :require_login

    def require_login
        unless logged_in?
            flash[:error] = "Please login to access the page!"
            redirect_to new_login_url
        end
    end

    def logged_in?
        # 一些判斷使用者是否登入的程式碼,傳回布林值
        ...
    end
end

如上定義之後,任何控制器的動作方法被呼叫之前,都會先呼叫require_login。同理,使用after_filter定義的方法,會在任何動作結束之後呼叫,使用around_filter定義的方法,會在任何動作執行前後呼叫。這三個方法可以搭配:only與:except,例如:

class LoginController < ApplicationController
    before_filter :require_login, :except => [:new, :create]
    ...
end

如上設定,則除了new與create之外,所有的動作之前都會先執行require_login

before_filter、after_filter和around_filter相反的是skip_before_filter、skip_after_filter和skip_around_filter,這用於取消曾使用before_filter、after_filter和around_filter定義的過濾器。例如若父類別曾定義過before_filter :require_login

class LoginController < ApplicationController
    skip_before_filter :require_login, :only => [:new, :create]

    ...
end

如上設定之後,除了new與create被取消之外,其它動作執行之前,都要套用過濾器。

before_filter、after_filter和around_filter定義的過濾器,會依定義順序由上往下執行,如果想依定義相反順序執行,則可以使用prepend_before_filter、prepend_after_filter和prepend_around_filter來定義。

過濾器還可以使用區塊定義,例如:

class ApplicationController < ActionController::Base
    before_filter do |controller|
        unless controller.send(:logged_in?)
            controller.flash[:error] = "You must be logged in"
            controller.redirect_to controller.new_login_url
        end

    end
end

如果你的過濾器是個通用元件,可以用於多個控制器,則可以將過濾器定義為類別:

class LoginFilter
    def self.filter(controller)
        unless controller.send(:logged_in?)
            controller.flash[:error] = "You must be logged in"
            controller.redirect_to controller.new_login_url
        end
    end
end

之後就可以這麼使用:

before_filter LoginFilter

實際上before_filter等可以接受的物件,只要擁有filter實例方法就可以了,所以也可以這麼定義:

class LoginFilter
    def filter(controller)
        unless controller.send(:logged_in?)
            controller.flash[:error] = "You must be logged in"
            controller.redirect_to controller.new_login_url
        end
    end
end