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.
