Pundit's conventions, from its own docs: a policy class per model

Free preview 3 min to read

A well-known gem, not installed in this app

Pundit is a widely used Ruby authorization gem, over a decade old and still maintained. This app's Gemfile and Gemfile.lock have no pundit line; the app never installed it. Before comparing anything, this course reads Pundit's conventions from its GitHub README (github.com/varvet/pundit), the way Authentication: Rails 8 read the generator's templates.

A policy class, named after the model it authorizes

Pundit's README states its core rule plainly: "The class has the same name as some kind of model class, only suffixed with the word 'Policy'." Its basic example:

class PostPolicy
  attr_reader :user, :post

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

  def update?
    user.admin? || !post.published?
  end
end

Post gets PostPolicy. initialize(user, post) takes two arguments: who's asking, and what they're asking about. update?, ending in a question mark, returns true or false: one permission check, named after the action it guards.

ApplicationPolicy: the base class Pundit's generator produces

Rails apps that install Pundit run rails g pundit:install, which generates an ApplicationPolicy for every other policy to inherit from. Written against that base, the same policy becomes:

class PostPolicy < ApplicationPolicy
  def update?
    user.admin? or not record.published?
  end
end

In the generated ApplicationPolicy, per Pundit's docs, "the model object is called record": a generic name, since ApplicationPolicy can't know in advance what kind of model each subclass authorizes.

Where these classes live

Pundit's convention puts every policy under app/policies/, one file per model: post_policy.rb for Post, comment_policy.rb for Comment. This app already has an app/policies/ directory, with twenty files in it. Lessons 3 and 4 read the four with Policy in their names and survey the rest.

What this course covers

Seven lessons, starting with Pundit's conventions from its own docs. This lesson covers policy classes and ApplicationPolicy. Lesson 2 covers the controller integration: authorize, policy_scope and Pundit::NotAuthorizedError. Then come this app's hand-built policies. Lesson 3 covers Identity::UserPolicy and Community::CommentPolicy, access-control policies, and where they're called. Lesson 4 covers two more files named Policy that answer a different question, and the sixteen files beside them that aren't policies in Pundit's sense at all. Lesson 5 sets the shape this app reached on its own next to Pundit's. Lesson 6 covers what adopting Pundit would change, including a naming mismatch in this app's code today. Lesson 7 puts it together, with a small Ruby challenge modeled on this app's access-control logic.

Lesson 1 of 7 · free

Keep going with lesson 2

Pundit's controller integration: authorize, policy_scope and NotAuthorizedError

Covers authorize, the shared Pundit::NotAuthorizedError rescue, policy_scope with a nested Scope class, and verify_authorized for development.

A free account also gives you the quizzes, your progress and notes, and the discussion.

Type to start searching...