+1

Giới thiệu về gem Pundit

Nếu bạn xây dựng một ứng dụng với nhiều loại user và điều bạn lo lắng nhất chính là phân quyền cho các user của bạn. Hiện tại có rất nhiều giải pháp cho vấn đề trên và một trong số đó là sử dụng gem pundit

Gem pundit là một thư viện giúp xây dựng một hệ thống hạn chế tài nguyên của một user được phép sử dụng.

Cài đặt

 gem "pundit"

Sau khi bundle, chạy dòng lệnh sau để sinh ra policy

rails g pundit:install

Để bắt đầu sử dụng gem Pundit, bạn cần include Pundit vào application_controller.rb như sau

class ApplicationController < ActionController::Base
  include Pundit
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
  protect_from_forgery with: :exception

  private
  def user_not_authorized
    flash[:error] = t "notification.not_admin"
    redirect_to request.referrer || new_user_session_path
  end

Sử dụng Pundit gem

Bạn cần restart Rails server để Rails có thể tìm thấy đường dẫn mới app/policies/. Tại đây bạn sẽ tìm thấy file mặc định của Pundit là application_policy.rb như sau:

class ApplicationPolicy
  attr_reader :user, :model

  def initialize current_user, model
    raise Pundit::NotAuthorizedError,"login" unless user
    @ user = user
    @ model = model
  end

  def index

  end

  def show
    scope.where(id: model.id).exists?
  end

  .
  .
  .

  def scope
    Pundit.policy_scope! user, model.class
  end

  class Scope
    attr_reader :user, :scope

    def initialize cuser, scope
      @ user = user
      @ scope = scope
    end

    def resolve
      scope
    end
  end
end

Khi đó ta thấy:

  • Tham số đầu tiên là một user. Trong controller, Pundit sẽ truyền vào current_user
  • Tham số thứ 2 là một model cần được authorize. Ở đây ta có thể không nhất thiết phải là một object của ActiveRecord hay là một ActiveModel, nó chỉ cần là một thực thể mà thôi.

Policy của pundit có các hàm tương ứng với các hàm trong controller để kiểm tra policy cho các hàm đó.

Ví dụ: Trong user_controller.rb của bạn:

class UsersController < ApplicationController

  def show
  end

  def index
    @ users = User.all
  end

 end

Khi đó trong user_policy.rb sẽ có các hàm tương ứng như sau:

class UserPolicy < ApplicationPolicy
  class Scope
    attr_reader :user, :scope

  def initialize user, scope
    @ user = user
    @ scope = scope
  end

  def index?
    @ user.present?
  end

  def show?
    @ user.present?
  end
 end

Chú ý

Với các hàm create, new và index ta cần authorize class User (Chúng ta sẽ thảo luận về lí do sau đó )

Sử dụng gem Pundit trong view

Sau khi sử lí ở controller, ta cần kiểm tra cả ở view để ẩn hiện các link phù hợp với từng action. Ví dụ views/posts/index.html.erb

<% if policy(user).edit? %>
  <td><%= link_to 'Edit', user, method: :put} %></td>
<% end %>

Kết luận

Trên đây mình đã giới thiệu với các bạn về gem Pundit, một sự lựa chọn đáng cân nhắc nếu bạn đang tìm kiếm giải pháp phân quyền cho ứng dụng Rails của mình. Còn nhiều vấn đề khác nhau cho gem này chúng ta sẽ thảo luận trong những bài tiếp theo. Cảm ơn đã tham khảo bài viết này

Nguồn tham khảo

https://github.com/elabs/pundit


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí