Pundit's conventions, from its own docs: a policy class per model
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.
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.