Filters

Posted by Anthony Chao on 2019-09-21

Filters

今天要來看的是這篇第八章的部分

Rails 中 filter 可以有 “before”, “after” 跟 “around” 這三個階段,表示這個東西要使用在每個 action 前 / 後 / 還是中間

很抽象嗎?來看看例子就懂囉!

因為 Rails Guide 的例子還滿清楚的,我就直接使用他們的例子講解了(絕對不是懶得自己打)

1
2
3
4
5
6
7
8
9
10
11
class ApplicationController < ActionController::Base
before_action :require_login

private
def require_login
unless logged_in?
flash[:error] = "You must be logged in to access this section"
redirect_to new_login_url # halts request cycle
end
end
end

在上面的例子中,定義了一個 private method require_login 並把它放在 filter before_action 中,所以在執行每個動作之前,都會先確認這個使用者的狀態是不是已經登入了

但這樣是有盲點的,你不可能到了一個新的頁面就已經是登入的狀態了(除非 cookie 已經儲存了),這時候可以用 skip_before_action 這個方法來設定例外

1
2
3
class LoginsController < ApplicationController
skip_before_action :require_login, only: [:new, :create]
end

around_action的使用比較複雜,在定義方法的時候一定要搭配 yield 來使用

1
2
3
4
5
6
7
8
9
10
11
class UsersController < ApplicationController
around_action :hoge

...
private
def hoge
logger.debug "執行前處理"
yield # 執行 action 裡面的內容
logger.debug "執行後處理"
end
end

Filter 其他用法

除了在 filter 後面接方法之外,還可以接 Block 或者 Class

1
2
3
4
5
6
7
8
class ApplicationController < ActionController::Base
before_action do |controller|
unless controller.send(:logged_in?)
flash[:error] = "You must be logged in to access this section"
redirect_to new_login_url
end
end
end

上面這邊要注意,因為 logged_in 是一個 private 方法,對於 private 方法是不能有對象的,因此要用 send 這個方法

1
2
3
4
5
6
7
8
9
10
11
12
13

class ApplicationController < ActionController::Base
before_action LoginFilter
end

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

在使用 class 的時候也要注意,這個 class 裡面的方法一定要呼應 filter 的種類,在這個例子中使用 before_action,所以裡面要有before 這個類別方法

參考資料
Rails Guide

Rails4でアクションの前後にフィルタ/処理を挟み込む





prevent_hack