12/08/2018, 15:05

Pundit for namespace

Có rất nhiều cách để sử dụng gem Pundit cho namespace, sau đây, mình sẽ giới thiệu 2 cách mình đã từng làm để check quyền cho user sử dụng gem Pundit. Cách 1: Sử dụng mặc định của Pundit gem Trong controller: users_controller.rb class Admin::UsersController < ApplicationController ...

Có rất nhiều cách để sử dụng gem Pundit cho namespace, sau đây, mình sẽ giới thiệu 2 cách mình đã từng làm để check quyền cho user sử dụng gem Pundit.

  1. Cách 1: Sử dụng mặc định của Pundit gem

Trong controller: users_controller.rb

  class Admin::UsersController < ApplicationController
    def index
       authorize [:admin, :user]
      @user = User.new
    end
    def show
        authorize [:admin, @user]
    end
  end

Trong file policy, ta vẫn định nghĩa các quyền như bình thường

class Admin::UserPolicy < ApplicationPolicy
  def index?
    current_user.admin?
  end
  
  def show?
      @user == current_user
  end
end

Cách này phù hợp khi bạn chỉ cần check các quyền cơ bản liên quan tới user mà thôi bởi ta không thể truyền được 1 đối tượng khác ngoài current_user và object cần truyền(trong trường hợp này là user). Điều này sẽ rất bất tiện trong trường hợp bạn muốn truyền những record khác sang cho policy.

  1. Cách 2: Custom hàm authorize của gem Ý tưởng: Hàm initialize của Pundit gem được def để nhận vào 2 biến là: current_user và record, chúng ta có thể coi record như một hash để định nghĩa các giá trị có thể truyền vào ở đó

Ta định nghĩa 1 hàm authorize_with_multiple với 2 biến truyền vào là 1 hash và class muốn gọi đến.

module Authorize
    def authorize_with_multiple args, policy
        pundit_policy = policy.new current_user, args
        query = "#{params[:action]}?"
        unless pundit_policy.public_send query
          error = Pundit::NotAuthorizedError.new "not allowed"
          raise error
        end
      end
end

Khi đó, ta có thể thoải mái truyền vào tất cả các object, biến, ... cần check policy Ví dụ: Trong file users_controller.rb ta có

class Admin::UsersController < ApplicationController
    def index
       authorize_with_multiple params.merge(address: Address.first, user: @user), Admin::UserPolicy
      @user = User.new
    end
    def show
        authorize_with_multiple params.merge(address: Address.first), Admin::UserPolicy
    end
  end

Làm như vậy, có nghĩa là ta đã định nghĩa lại record được truyền sang policy của Admin::UserPolicy không chỉ có current_user, mà còn có address và user Ở Admin::UserPolicy, ta có thể gọi ra 1 cách dễ dàng giá trị truyền vào như cách gọi 1 hash record[:address] hay record[:user]. Cách này phù hợp khi bạn cần check policy trên nhiều biến, hay object. Mong rằng các bạn có thể chọn cho mình cách check policy phù hợp với nhu cầu của mình!

0