iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
0

嗨!各位朋友大家好,打給後,歹嘎吼,胎尬喉,我是阿圓,一樣有請今天的one piece:

(雷利大叔!!)

鐵人賽的進度來到三分之二了呢!今天想跟各位來介紹 pundit 這個平常在專案裡面,使用程度很高的gem!

權限管理系統(pundit)

若今天的專案比較複雜一點,你可能會需要定義一下 user 權限,除了在controller裡寫下一大堆if...else判斷外,你有另一個選項是使用pundit 這個 gem。

pundit 會在資料夾中生成與 controller 同名的 policy,而你可以在 policy 去定義跟與各個 action 有關的權限。

基本安裝

首先無例外的記得先到 gemfile :
gem "pundit"
(記得bundle)

接著,到 application controller的檔案裡面引入:

class ApplicationController < ActionController::Base
  include Pundit
end

最後,記得執行pundit的安裝:
rails g pundit:install

這樣,就會長出app/policies/的這個資料夾,設定好後,就可以在controller、view 裡使用了!

rails g pundit:policy post
就會幫你建立 post 的 policy 了!

使用方法

policy 設定方法呢,就是定義檢查登入者(user) 有沒有辦法對資料(record) 進行某種操作 (update?),而一般來說,policy 遵從以下幾點:

  1. policy 裡的類別命名,都是 modle 名稱後面接 Policy
  2. policy 接收兩個參數,第一個是 user ,而預設會呼叫 current_user 這個方法,若沒有使用 devise 這個 gem ,請記得作一個給他!
  3. 第二個參數是想要驗證能否執行操作的 model(ex:post)
  4. policy 裡的方法名,一般都是使用 action 的名稱後面加個問號(ex:update?)
class PostPolicy
  attr_reader :user, :post

  def initialize(user, post)
    @user = user
    @post = post
  end

  def update?
    user.admin? or not post.published?
  end
end

以上方的例子,我們可以在 post_controller 裡使用authorize這個方法:

def update
  @post = Post.find(params[:id])
  authorize @post
  if @post.update(post_params)
    redirect_to @post
  else
    render :edit
  end
end

就會去執行 post_policy 內的update?方法。

你也可以在不同的 action 裡,要求與 action 不同名的驗證:

def publish
  @post = Post.find(params[:id])
  authorize @post, :update?
  @post.publish!
  redirect_to @post
end

也可以在view裡面呼叫他:

<% if policy(@post).update? %>
  <%= link_to "Edit post", edit_post_path(@post) %>
<% end %>

以上是比較基本的用法!

如果想某些 user 來做驗證,可以使用scope:

class PostPolicy < ApplicationPolicy
  class Scope
    def initialize(user, scope)
      @user  = user
      @scope = scope
    end

    def resolve
      if user.admin?
        scope.all
      else
        scope.where(published: true)
      end
    end

    private

    attr_reader :user, :scope
  end

  def update?
    user.admin? or not record.published?
  end
end

特別要說的是,pundit 也能處理 params:

# in policy
class PostPolicy < ApplicationPolicy
  def permitted_attributes
    if user.admin? || user.owner_of?(post)
      [:title, :body, :tag_list]
    else
      [:tag_list]
    end
  end
end

# in controller
def update
  @post = Post.find(params[:id])
  if @post.update_attributes(permitted_attributes(@post))
    redirect_to @post
  else
    render :edit
  end
end

也可以針對不同action,有不同的permitted_attributes

class PostPolicy < ApplicationPolicy
  def permitted_attributes_for_create
    [:title, :body]
  end

  def permitted_attributes_for_edit
    [:body]
  end
end

以上就是有關 pundit 的基本介紹啦!感謝各位看到這邊,若有任何建議,請各位不吝指教!我們明天見!


上一篇
Day_19 active Storage ?
下一篇
Day_21 nokogiri ?
系列文
Ruby on Rails 新手的30個問題!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言