Filter là các phương thức chạy trước, sau hoặc cùng với một phương thức action (phương thức của controller).
Các phương thức filter có tính thừa kế, tức là nếu chúng ta gọi các phương thức filter trong lớp ApplicationController,
thì các lớp kế thừa nó cũng chạy các phương thức filter đó.
Trong phần này chúng ta sẽ sử dụng filter để chặn truy cập vào trang /admin/index
nếu người dùng chưa đăng nhập.
Đầu tiên chúng ta sửa lại lớp ApplicationController
như sau:
class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. before_filter :authorize protect_from_forgery with: :exception private def current_cart Cart.find(session[:cart_id]) rescue ActiveRecord::RecordNotFound cart = Cart.create session[:cart_id] = cart.id cart end helper_method :current_cart protected def authorize @user = User.find_by_id(session[:user_id]) if @user == nil redirect_to '/login', :notice => 'You must login first' end end end
Filter có 3 loại là before, after và around, tương ứng với chạy trước, sau hoặc chạy cùng.
Ở đây chúng ta dùng phương thức before_filter,
và truyền vào tham số :authorize,
đây là phương thức kiểm tra xem người dùng có đăng nhập hay chưa do chúng ta tự định nghĩa. Nếu người dùng chưa đăng nhập thì chúng ta cho trỏ tới trang /login
.
Phương thức authorize
sẽ chạy trước các phương thức action khác, tuy nhiên có một vấn đề, như đã nói ở trên là các filter sẽ được thừa kế, tức là các lớp controller con cũng sẽ chạy dòng before_filter
ở trên. Trong số các controller kế thừa có cả controller chịu trách nhiệm việc hiển thị trang /login,
tức là ở đây chúng ta không cho người dùng đăng nhập luôn.
Để giải quyết việc này thì chúng ta dùng các phương thức skip, ví dụ chúng ta thêm dòng này vào đầu lớp SessionsController
như sau:
class SessionsController < ApplicationController skip_before_filter :authorize . . . end
Có thể hiểu phương thức skip_before_filter :authorize
sẽ đưa phương thức authorize
vào danh sách “đen”, tức là không được chạy. Và do đó chúng ta có thể chạy các phương thức khác bình thường.
Và không chỉ có lớp SessionsController
mà tất cả các lớp controller con khác cũng cần được “mở khóa” nữa. Chúng ta lần lượt sửa lại như sau:
Lớp StoreController:
class StoreController < ApplicationController skip_before_filter :authorize . . . end
Lớp CartsController:
class CartsController < ApplicationController skip_before_filter :authorize, :only => [:create, :update, :destroy] . . . end
Chúng ta có thể truyền vào tham số :only,
tham số này sẽ quy định chỉ có một số phương thức nhất định được “mở khóa”.
Lớp LineItemsController:
class LineItemsController < ApplicationController skip_before_filter :authorize, :only => :create . . . end
Lớp OrdersController:
class OrdersController < ApplicationController skip_before_filter :authorize, :only => [:new, :create] . . . end
Vậy là xong, bây giờ nếu chúng ta vào trang /admin/index
hay một số trang nhất định mà chưa đăng nhập thì chúng ta sẽ được trỏ về trang /login.
Bạn có thể tìm hiểu thêm về các phương thức filter tại đây.