https://github.com/varvet/pundit
Minimal authorization through OO design and pure Ruby classes
https://github.com/varvet/pundit
Keywords
ruby
Keywords from Contributors
activerecord activejob mvc rspec rubygems rack rubocop feature-flag crash-reporting ruby-gem
Last synced: about 21 hours ago
JSON representation
Repository metadata
Minimal authorization through OO design and pure Ruby classes
- Host: GitHub
- URL: https://github.com/varvet/pundit
- Owner: varvet
- License: mit
- Created: 2012-11-04T09:20:19.000Z (over 13 years ago)
- Default Branch: main
- Last Pushed: 2026-01-08T12:16:14.000Z (about 2 months ago)
- Last Synced: 2026-02-19T20:38:30.639Z (12 days ago)
- Topics: ruby
- Language: Ruby
- Homepage:
- Size: 697 KB
- Stars: 8,476
- Watchers: 98
- Forks: 643
- Open Issues: 14
- Releases: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.txt
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
README.md
Pundit
Pundit provides a set of helpers which guide you in leveraging regular Ruby
classes and object oriented design patterns to build a straightforward, robust, and
scalable authorization system.
Links:
Sponsored by: Varvet
Installation
Please note that the README on GitHub is accurate with the latest code on GitHub. You are most likely using a released version of Pundit, so please refer to the documentation for the latest released version of Pundit.
bundle add pundit
Include Pundit::Authorization in your application controller:
class ApplicationController < ActionController::Base
include Pundit::Authorization
end
Optionally, you can run the generator, which will set up an application policy
with some useful defaults for you:
rails g pundit:install
After generating your application policy, restart the Rails server so that Rails
can pick up any classes in the new app/policies/ directory.
Policies
Pundit is focused around the notion of policy classes. We suggest that you put
these classes in app/policies. This is an example that allows updating a post
if the user is an admin, or if the post is unpublished:
class PostPolicy
attr_reader :user, :post
def initialize(user, post)
@user = user
@post = post
end
def update?
user.admin? || !post.published?
end
end
As you can see, this is a plain Ruby class. Pundit makes the following
assumptions about this class:
- The class has the same name as some kind of model class, only suffixed
with the word "Policy". - The first argument is a user. In your controller, Pundit will call the
current_usermethod to retrieve what to send into this argument - The second argument is some kind of model object, whose authorization
you want to check. This does not need to be an ActiveRecord or even
an ActiveModel object, it can be anything really. - The class implements some kind of query method, in this case
update?.
Usually, this will map to the name of a particular controller action.
That's it really.
Usually you'll want to inherit from the application policy created by the
generator, or set up your own base class to inherit from:
class PostPolicy < ApplicationPolicy
def update?
user.admin? or not record.published?
end
end
In the generated ApplicationPolicy, the model object is called record.
Supposing that you have an instance of class Post, Pundit now lets you do
this in your controller:
def update
@post = Post.find(params[:id])
authorize @post
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
The authorize method automatically infers that Post will have a matching
PostPolicy class, and instantiates this class, handing in the current user
and the given record. It then infers from the action name, that it should call
update? on this instance of the policy. In this case, you can imagine that
authorize would have done something like this:
unless PostPolicy.new(current_user, @post).update?
raise Pundit::NotAuthorizedError, "not allowed to PostPolicy#update? this Post"
end
You can pass a second argument to authorize if the name of the permission you
want to check doesn't match the action name. For example:
def publish
@post = Post.find(params[:id])
authorize @post, :update?
@post.publish!
redirect_to @post
end
You can pass an argument to override the policy class if necessary. For example:
def create
@publication = find_publication # assume this method returns any model that behaves like a publication
# @publication.class => Post
authorize @publication, policy_class: PublicationPolicy
@publication.publish!
redirect_to @publication
end
If you don't have an instance for the first argument to authorize, then you can pass
the class. For example:
Policy:
class PostPolicy < ApplicationPolicy
def admin_list?
user.admin?
end
end
Controller:
def admin_list
authorize Post # we don't have a particular post to authorize
# Rest of controller action
end
authorize returns the instance passed to it, so you can chain it like this:
Controller:
def show
@user = authorize User.find(params[:id])
end
# return the record even for namespaced policies
def show
@user = authorize [:admin, User.find(params[:id])]
end
You can easily get a hold of an instance of the policy through the policy
method in both the view and controller. This is especially useful for
conditionally showing links or buttons in the view:
<% if policy(@post).update? %>
<%= link_to "Edit post", edit_post_path(@post) %>
<% end %>
Headless policies
Given there is a policy without a corresponding model / ruby class,
you can retrieve it by passing a symbol.
# app/policies/dashboard_policy.rb
class DashboardPolicy
attr_reader :user
# `_record` in this example will be :dashboard
def initialize(user, _record)
@user = user
end
def show?
user.admin?
end
end
Note that the headless policy still needs to accept two arguments. The
second argument will be the symbol :dashboard in this case, which
is what is passed as the record to authorize below.
# In controllers
def show
authorize :dashboard, :show?
...
end
# In views
<% if policy(:dashboard).show? %>
<%= link_to 'Dashboard', dashboard_path %>
<% end %>
Scopes
Often, you will want to have some kind of view listing records which a
particular user has access to. When using Pundit, you are expected to
define a class called a policy scope. It can look something like this:
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 makes the following assumptions about this class:
- The class has the name
Scopeand is nested under the policy class. - The first argument is a user. In your controller, Pundit will call the
current_usermethod to retrieve what to send into this argument. - The second argument is a scope of some kind on which to perform some kind of
query. It will usually be an ActiveRecord class or a
ActiveRecord::Relation, but it could be something else entirely. - Instances of this class respond to the method
resolve, which should return
some kind of result which can be iterated over. For ActiveRecord classes,
this would usually be anActiveRecord::Relation.
You'll probably want to inherit from the application policy scope generated by the
generator, or create your own base class to inherit from:
class PostPolicy < ApplicationPolicy
class Scope < ApplicationPolicy::Scope
def resolve
if user.admin?
scope.all
else
scope.where(published: true)
end
end
end
def update?
user.admin? or not record.published?
end
end
You can now use this class from your controller via the policy_scope method:
def index
@posts = policy_scope(Post)
end
def show
@post = policy_scope(Post).find(params[:id])
end
Like with the authorize method, you can also override the policy scope class:
def index
# publication_class => Post
@publications = policy_scope(publication_class, policy_scope_class: PublicationPolicy::Scope)
end
In this case it is a shortcut for doing:
def index
@publications = PublicationPolicy::Scope.new(current_user, Post).resolve
end
You can, and are encouraged to, use this method in views:
<% policy_scope(@user.posts).each do |post| %>
<p><%= link_to post.title, post_path(post) %></p>
<% end %>
Ensuring policies and scopes are used
When you are developing an application with Pundit it can be easy to forget to
authorize some action. People are forgetful after all. Since Pundit encourages
you to add the authorize call manually to each controller action, it's really
easy to miss one.
Thankfully, Pundit has a handy feature which reminds you in case you forget.
Pundit tracks whether you have called authorize anywhere in your controller
action. Pundit also adds a method to your controllers called
verify_authorized. This method will raise an exception if authorize has not
yet been called. You should run this method in an after_action hook to ensure
that you haven't forgotten to authorize the action. For example:
class ApplicationController < ActionController::Base
include Pundit::Authorization
after_action :verify_authorized
end
Likewise, Pundit also adds verify_policy_scoped to your controller. This
will raise an exception similar to verify_authorized. However, it tracks
if policy_scope is used instead of authorize. This is mostly useful for
controller actions like index which find collections with a scope and don't
authorize individual instances.
class ApplicationController < ActionController::Base
include Pundit::Authorization
after_action :verify_pundit_authorization
def verify_pundit_authorization
if action_name == "index"
verify_policy_scoped
else
verify_authorized
end
end
end
This verification mechanism only exists to aid you while developing your
application, so you don't forget to call authorize. It is not some kind of
failsafe mechanism or authorization mechanism. You should be able to remove
these filters without affecting how your app works in any way.
Some people have found this feature confusing, while many others
find it extremely helpful. If you fall into the category of people who find it
confusing then you do not need to use it. Pundit will work fine without
using verify_authorized and verify_policy_scoped.
Conditional verification
If you're using verify_authorized in your controllers but need to
conditionally bypass verification, you can use skip_authorization. For
bypassing verify_policy_scoped, use skip_policy_scope. These are useful
in circumstances where you don't want to disable verification for the
entire action, but have some cases where you intend to not authorize.
def show
record = Record.find_by(attribute: "value")
if record.present?
authorize record
else
skip_authorization
end
end
Manually specifying policy classes
Sometimes you might want to explicitly declare which policy to use for a given
class, instead of letting Pundit infer it. This can be done like so:
class Post
def self.policy_class
PostablePolicy
end
end
Alternatively, you can declare an instance method:
class Post
def policy_class
PostablePolicy
end
end
Plain old Ruby
Pundit is a very small library on purpose, and it doesn't do anything you can't do yourself. There's no secret sauce here. It does as little as possible, and then gets out of your way.
With the few but powerful helpers available in Pundit, you have the power to build a well structured, fully working authorization system without using any special DSLs or funky syntax.
Remember that all of the policy and scope classes are plain Ruby classes, which means you can use the same mechanisms you always use to DRY things up. Encapsulate a set of permissions into a module and include them in multiple policies. Use alias_method to make some permissions behave the same as others. Inherit from a base set of permissions. Use metaprogramming if you really have to.
Generator
Use the supplied generator to generate policies:
rails g pundit:policy post
Closed systems
In many applications, only logged in users are really able to do anything. If
you're building such a system, it can be kind of cumbersome to check that the
user in a policy isn't nil for every single permission. Aside from policies,
you can add this check to the base class for scopes.
We suggest that you define a filter that redirects unauthenticated users to the
login page. As a secondary defence, if you've defined an ApplicationPolicy, it
might be a good idea to raise an exception if somehow an unauthenticated user
got through. This way you can fail more gracefully.
class ApplicationPolicy
def initialize(user, record)
raise Pundit::NotAuthorizedError, "must be logged in" unless user
@user = user
@record = record
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
raise Pundit::NotAuthorizedError, "must be logged in" unless user
@user = user
@scope = scope
end
end
end
NilClassPolicy
To support a null object pattern
you may find that you want to implement a NilClassPolicy. This might be useful
where you want to extend your ApplicationPolicy to allow some tolerance of, for
example, associations which might be nil.
class NilClassPolicy < ApplicationPolicy
class Scope < ApplicationPolicy::Scope
def resolve
raise Pundit::NotDefinedError, "Cannot scope NilClass"
end
end
def show?
false # Nobody can see nothing
end
end
Rescuing a denied Authorization in Rails
Pundit raises a Pundit::NotAuthorizedError you can
rescue_from
in your ApplicationController. You can customize the user_not_authorized
method in every controller.
class ApplicationController < ActionController::Base
include Pundit::Authorization
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
private
def user_not_authorized
flash[:alert] = "You are not authorized to perform this action."
redirect_back_or_to(root_path)
end
end
Alternatively, you can globally handle Pundit::NotAuthorizedError's by having rails handle them as a 403 error and serving a 403 error page. Add the following to application.rb:
config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden
Creating custom error messages
NotAuthorizedErrors provide information on what query (e.g. :create?), what
record (e.g. an instance of Post), and what policy (e.g. an instance of
PostPolicy) caused the error to be raised.
One way to use these query, record, and policy properties is to connect
them with I18n to generate error messages. Here's how you might go about doing
that.
class ApplicationController < ActionController::Base
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
private
def user_not_authorized(exception)
policy_name = exception.policy.class.to_s.underscore
flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default
redirect_back_or_to(root_path)
end
end
en:
pundit:
default: 'You cannot perform this action.'
post_policy:
update?: 'You cannot edit this post!'
create?: 'You cannot create posts!'
This is an example. Pundit is agnostic as to how you implement your error messaging.
Manually retrieving policies and scopes
Sometimes you want to retrieve a policy for a record outside the controller or
view. For example when you delegate permissions from one policy to another.
You can easily retrieve policies and scopes like this:
Pundit.policy!(user, post)
Pundit.policy(user, post)
Pundit.policy_scope!(user, Post)
Pundit.policy_scope(user, Post)
The bang methods will raise an exception if the policy does not exist, whereas
those without the bang will return nil.
Customize Pundit user
On occasion, your controller may be unable to access current_user, or the method that should be invoked by Pundit may not be current_user. To address this, you can define a method in your controller named pundit_user.
def pundit_user
User.find_by_other_means
end
For instance, Rails 8 includes a built-in authentication generator. If you choose to use it, the currently logged-in user is accessed via Current.user instead of current_user.
To ensure compatibility with Pundit, define a pundit_user method in application_controller.rb (or another suitable location) as follows:
def pundit_user
Current.user
end
Handling User Switching in Pundit
When switching users in your application, it's important to reset the Pundit user context to ensure that authorization policies are applied correctly for the new user. Pundit caches the user context, so failing to reset it could result in incorrect permissions being applied.
To handle user switching, you can use the following pattern in your controller:
class ApplicationController
include Pundit::Authorization
def switch_user_to(user)
terminate_session if authenticated?
start_new_session_for user
pundit_reset!
end
end
Make sure to invoke pundit_reset! whenever changing the user. This ensures the cached authorization context is reset, preventing any incorrect permissions from being applied.
Policy Namespacing
In some cases it might be helpful to have multiple policies that serve different contexts for a
resource. A prime example of this is the case where User policies differ from Admin policies. To
authorize with a namespaced policy, pass the namespace into the authorize helper in an array:
authorize(post) # => will look for a PostPolicy
authorize([:admin, post]) # => will look for an Admin::PostPolicy
authorize([:foo, :bar, post]) # => will look for a Foo::Bar::PostPolicy
policy_scope(Post) # => will look for a PostPolicy::Scope
policy_scope([:admin, Post]) # => will look for an Admin::PostPolicy::Scope
policy_scope([:foo, :bar, Post]) # => will look for a Foo::Bar::PostPolicy::Scope
If you are using namespaced policies for something like Admin views, it can be useful to
override the policy_scope and authorize helpers in your AdminController to automatically
apply the namespacing:
class AdminController < ApplicationController
def policy_scope(scope)
super([:admin, scope])
end
def authorize(record, query = nil)
super([:admin, record], query)
end
end
class Admin::PostController < AdminController
def index
policy_scope(Post)
end
def show
post = authorize Post.find(params[:id])
end
end
Additional context
Pundit strongly encourages you to model your application in such a way that the
only context you need for authorization is a user object and a domain model that
you want to check authorization for. If you find yourself needing more context than
that, consider whether you are authorizing the right domain model, maybe another
domain model (or a wrapper around multiple domain models) can provide the context
you need.
Pundit does not allow you to pass additional arguments to policies for precisely
this reason.
However, in very rare cases, you might need to authorize based on more context than just
the currently authenticated user. Suppose for example that authorization is dependent
on IP address in addition to the authenticated user. In that case, one option is to
create a special class which wraps up both user and IP and passes it to the policy.
class UserContext
attr_reader :user, :ip
def initialize(user, ip)
@user = user
@ip = ip
end
end
class ApplicationController
include Pundit::Authorization
def pundit_user
UserContext.new(current_user, request.ip)
end
end
Strong parameters
In Rails, mass-assignment protection is handled in the controller. With Pundit you can control which attributes a user has access to update via your policies. You can set up an expected_attributes_for_action(action_name) method in your policy like this:
# app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
def expected_attributes_for_action(_action_name)
if user.admin? || user.owner_of?(post)
[:title, :body, :tag_list]
else
[:tag_list]
end
end
end
You can now retrieve these attributes from the policy:
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def update
@post = Post.find(params[:id])
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
private
def post_params
params.expect(policy(@post).expected_attributes)
end
end
However, this is a bit cumbersome, so Pundit provides a convenient helper method with #expected_attributes:
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def update
@post = Post.find(params[:id])
if @post.update(expected_attributes(@post))
redirect_to @post
else
render :edit
end
end
end
Pundit still support the old params.require.permit() style of permitting attributes, although params.expect() is preferred.
If you need to fetch parameters based on namespaces different from the suggested one, override the below method, in your controller, and return an instance of ActionController::Parameters.
def pundit_params_for(record)
params.require(PolicyFinder.new(record).param_key)
end
For example:
# If you don't want to use require
def pundit_params_for(record)
params.fetch(PolicyFinder.new(record).param_key, {})
end
# If you are using something like the JSON API spec
def pundit_params_for(_record)
params.fetch(:data, {}).fetch(:attributes, {})
end
RSpec
Policy Specs
[!TIP]
An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this
excellent post and implemented in the third party pundit-matchers gem.
Pundit includes a mini-DSL for writing expressive tests for your policies in RSpec.
Require pundit/rspec in your spec_helper.rb:
require "pundit/rspec"
Then put your policy specs in spec/policies, and make them look somewhat like this:
describe PostPolicy do
subject { described_class }
permissions :update?, :edit? do
it "denies access if post is published" do
expect(subject).not_to permit(User.new(admin: false), Post.new(published: true))
end
it "grants access if post is published and user is an admin" do
expect(subject).to permit(User.new(admin: true), Post.new(published: true))
end
it "grants access if post is unpublished" do
expect(subject).to permit(User.new(admin: false), Post.new(published: false))
end
end
end
Custom matcher description
By default rspec includes an inspected user and record in the matcher description, which might become overly verbose:
PostPolicy
update? and show?
is expected to permit #<User:0x0000000104aefd80> and #<Post:0x0000000104aef8d0 @user=#<User:0x0000000104aefd80>>
You can override the default description with a static string, or a block:
# static alternative: Pundit::RSpec::Matchers.description = "permit the user"
Pundit::RSpec::Matchers.description = ->(user, record) do
"permit user with role #{user.role} to access record with ID #{record.id}"
end
Which would make for a less chatty output:
PostPolicy
update? and show?
is expected to permit user with role admin to access record with ID 130
Focus Support
If your RSpec config has filter_run_when_matching :focus, you may tag the permissions helper like so:
permissions :show?, :focus do
Scope Specs
Pundit does not provide a DSL for testing scopes. Test them like you would a regular Ruby class!
Linting with RuboCop RSpec
When you lint your RSpec spec files with rubocop-rspec, it will fail to properly detect RSpec constructs that Pundit defines, permissions.
Make sure to use rubocop-rspec 2.0 or newer and add the following to your .rubocop.yml:
inherit_gem:
pundit: config/rubocop-rspec.yml
External Resources
- RailsApps Example Application: Pundit and Devise
- Migrating to Pundit from CanCan
- Testing Pundit Policies with RSpec
- Testing Pundit with Minitest
- Using Pundit outside of a Rails controller
- Straightforward Rails Authorization with Pundit
Other implementations
- Flask-Pundit (Python) is a Flask extension "heavily inspired by" Pundit
License
Licensed under the MIT license, see the separate LICENSE.txt file.
Owner metadata
- Name: Varvet
- Login: varvet
- Email: hello@varvet.com
- Kind: organization
- Description:
- Website: https://www.varvet.com
- Location: Gothenburg, Sweden
- Twitter: varvet
- Company:
- Icon url: https://avatars.githubusercontent.com/u/3612746?v=4
- Repositories: 127
- Last ynced at: 2024-04-14T19:00:51.817Z
- Profile URL: https://github.com/varvet
GitHub Events
Total
- Delete event: 13
- Pull request event: 31
- Fork event: 25
- Issues event: 16
- Watch event: 207
- Issue comment event: 68
- Push event: 40
- Pull request review comment event: 3
- Pull request review event: 5
- Create event: 12
Last Year
- Delete event: 7
- Pull request event: 18
- Fork event: 11
- Issues event: 7
- Watch event: 107
- Issue comment event: 41
- Push event: 25
- Pull request review comment event: 2
- Pull request review event: 1
- Create event: 10
Committers metadata
Last synced: 6 days ago
Total Commits: 504
Total Committers: 147
Avg Commits per committer: 3.429
Development Distribution Score (DDS): 0.794
Commits in past year: 29
Committers in past year: 3
Avg Commits per committer in past year: 9.667
Development Distribution Score (DDS) in past year: 0.207
| Name | Commits | |
|---|---|---|
| Kim Burgestrand | k****m@b****e | 104 |
| Jonas Nicklas | j****s@g****m | 62 |
| Linus Marton | l****n@g****m | 43 |
| Duncan Stuart | d****t@g****m | 28 |
| Thomas Klemm | g****b@t****u | 26 |
| Olle Jonsson | o****n@g****m | 16 |
| Furkan Ural | f****n@f****v | 10 |
| Sjors Smits | s****s@g****m | 9 |
| Pablo Crivella | p****a@g****m | 7 |
| qwyng | i****i@g****m | 6 |
| Jiazhen Xie | f****5@g****m | 5 |
| Jonas Nicklas and Kim Burgestrand | d****m@e****e | 5 |
| Étienne Barrié | e****e@g****m | 4 |
| John Otander | j****r@g****m | 4 |
| Brendan Thomas | b****9@g****m | 4 |
| Jason Daly | me@j****e | 4 |
| Chris Alley | c****s@c****o | 3 |
| Geremia Taglialatela | t****v@g****m | 3 |
| Jay Hayes | ur@i****m | 3 |
| Johan André | j****n@s****e | 3 |
| Marcelo Guimarães | m****i@g****m | 3 |
| Ryuichiro Suzuki | d****r@g****m | 3 |
| Ulysse Carion | u****n@g****m | 3 |
| Yoshiyuki Hirano | y****o@m****m | 3 |
| Eduardo Gutierrez | e****o@v****m | 3 |
| Philip Vieira | p****p@v****e | 3 |
| Justin Gordon | j****n@g****m | 2 |
| Max Calabrese | m****e@y****m | 2 |
| René Föhring | rf@b****e | 2 |
| Sean Devine | s****e@x****m | 2 |
| and 117 more... | ||
Committer domains:
- me.com: 3
- elabs.se: 2
- lomography.com: 2
- blacklane.com: 1
- deefour.me: 1
- siami.fr: 1
- trust-nickol.de: 1
- makropod.se: 1
- babbel.com: 1
- yandex.ru: 1
- bisdn.de: 1
- chartmogul.com: 1
- engineyard.com: 1
- ruslan.sk: 1
- asperasoft.com: 1
- redilio.us: 1
- weiskotten.com: 1
- bignerdranch.com: 1
- iangreenleaf.com: 1
- envek.name: 1
- iwa.fi: 1
- x-b-e.com: 1
- bamaru.de: 1
- ymail.com: 1
- vallin.se: 1
- vermonster.com: 1
- significantbit.se: 1
- iamvery.com: 1
- chrisalley.info: 1
- jasondaly.name: 1
- furkanural.dev: 1
- tklemm.eu: 1
- burgestrand.se: 1
- appropriate.io: 1
- fqxp.de: 1
- fdo.cr: 1
- dylanfm.com: 1
- ramaboo.com: 1
- danielkehoe.com: 1
- carbonfive.com: 1
- benjaminfleischer.com: 1
- skillstream.co.uk: 1
- nano3labs.com: 1
- iki.fi: 1
- igels.net: 1
- aranda.dev: 1
- ivanstorck.com: 1
- disney.com: 1
- harigopal.in: 1
- globalapptesting.com: 1
- rewind.io: 1
- spbtv.com: 1
- oriontransfer.co.nz: 1
- ryanlue.com: 1
- fbsdata.com: 1
- ross-hunter.com: 1
- qmoya.com: 1
- vanstee.me: 1
- pantographe.studio: 1
- nathanmlong.com: 1
- benle.de: 1
- wojtekmach.pl: 1
- goodworksonearth.org: 1
- tieto.com: 1
- latrobest.com: 1
- rails-royce.org: 1
Issue and Pull Request metadata
Last synced: about 2 months ago
Total issues: 79
Total pull requests: 155
Average time to close issues: 10 months
Average time to close pull requests: 6 months
Total issue authors: 72
Total pull request authors: 58
Average comments per issue: 3.73
Average comments per pull request: 1.78
Merged pull request: 94
Bot issues: 0
Bot pull requests: 0
Past year issues: 8
Past year pull requests: 24
Past year average time to close issues: 10 days
Past year average time to close pull requests: 3 days
Past year issue authors: 6
Past year pull request authors: 5
Past year average comments per issue: 1.88
Past year average comments per pull request: 1.33
Past year merged pull request: 18
Past year bot issues: 0
Past year bot pull requests: 0
Top Issue Authors
- Burgestrand (6)
- james-em (2)
- sedubois (2)
- wonderphil (1)
- bmulholland (1)
- joelzwarrington (1)
- MyklClason (1)
- Linuus (1)
- rlue (1)
- Pharserror (1)
- matthewjsummers (1)
- martingregoire (1)
- jamesst20 (1)
- alec-c4 (1)
- viamin (1)
Top Pull Request Authors
- Burgestrand (64)
- tagliala (8)
- hobbypunk90 (3)
- kenboo0426 (2)
- barelyknown (2)
- langsharpe (2)
- eizengan (2)
- m-nakamura145 (2)
- boof (2)
- gregfletch (2)
- andyw8 (2)
- furkanural (2)
- SuzukiRyuichiro (2)
- Numie (2)
- javierav (2)
Top Issue Labels
- feature request (9)
- waiting for response (8)
- good first issue (7)
- problem (4)
- needs reproduction (3)
- question (3)
- documentation (3)
- simmering (2)
- wontfix (1)
Top Pull Request Labels
- waiting for response (11)
- simmering (5)
- good first issue (4)
- documentation (2)
- needs updating (2)
- feature request (1)
- problem (1)
Package metadata
- Total packages: 10
-
Total downloads:
- rubygems: 190,748,437 total
- Total docker downloads: 267,280,196
- Total dependent packages: 119 (may contain duplicates)
- Total dependent repositories: 10,668 (may contain duplicates)
- Total versions: 72
- Total maintainers: 3
gem.coop: pundit
Object oriented authorization for Rails applications
- Homepage: https://github.com/varvet/pundit
- Documentation: http://www.rubydoc.info/gems/pundit/
- Licenses: MIT
- Latest release: 2.5.2 (published 5 months ago)
- Last Synced: 2026-02-27T04:30:38.386Z (5 days ago)
- Versions: 22
- Dependent Packages: 0
- Dependent Repositories: 0
- Downloads: 95,383,360 Total
- Docker Downloads: 133,640,098
-
Rankings:
- Dependent repos count: 0.0%
- Dependent packages count: 0.0%
- Average: 0.194%
- Downloads: 0.279%
- Docker downloads count: 0.499%
- Maintainers (3)
rubygems.org: pundit
Object oriented authorization for Rails applications
- Homepage: https://github.com/varvet/pundit
- Documentation: http://www.rubydoc.info/gems/pundit/
- Licenses: MIT
- Latest release: 2.5.2 (published 5 months ago)
- Last Synced: 2026-02-26T22:30:52.609Z (5 days ago)
- Versions: 22
- Dependent Packages: 119
- Dependent Repositories: 10,667
- Downloads: 95,365,077 Total
- Docker Downloads: 133,640,098
-
Rankings:
- Stargazers count: 0.144%
- Dependent packages count: 0.293%
- Dependent repos count: 0.327%
- Downloads: 0.336%
- Average: 0.435%
- Docker downloads count: 0.599%
- Forks count: 0.908%
- Maintainers (3)
proxy.golang.org: github.com/varvet/pundit
- Homepage:
- Documentation: https://pkg.go.dev/github.com/varvet/pundit#section-documentation
- Licenses: mit
- Latest release: v2.5.2+incompatible (published 5 months ago)
- Last Synced: 2026-02-25T22:02:28.677Z (6 days ago)
- Versions: 21
- Dependent Packages: 0
- Dependent Repositories: 1
-
Rankings:
- Stargazers count: 0.732%
- Forks count: 1.149%
- Average: 3.783%
- Dependent repos count: 4.79%
- Dependent packages count: 8.463%
debian-11: ruby-pundit
- Homepage: https://github.com/varvet/pundit
- Documentation: https://packages.debian.org/bullseye/ruby-pundit
- Licenses:
- Latest release: 2.1.0-1 (published 21 days ago)
- Last Synced: 2026-02-13T08:23:32.566Z (19 days ago)
- Versions: 1
- Dependent Packages: 0
- Dependent Repositories: 0
-
Rankings:
- Dependent repos count: 0.0%
- Dependent packages count: 0.0%
- Average: 100%
debian-12: ruby-pundit
- Homepage: https://github.com/varvet/pundit
- Documentation: https://packages.debian.org/bookworm/ruby-pundit
- Licenses:
- Latest release: 2.1.0-1 (published 19 days ago)
- Last Synced: 2026-02-12T23:38:00.272Z (19 days ago)
- Versions: 1
- Dependent Packages: 0
- Dependent Repositories: 0
-
Rankings:
Dependencies
- actionpack >= 3.0.0 development
- activemodel >= 3.0.0 development
- bundler >= 0 development
- pry >= 0 development
- railties >= 3.0.0 development
- rake >= 0 development
- rspec >= 3.0.0 development
- rubocop = 1.24.0 development
- simplecov >= 0.17.0 development
- yard >= 0 development
- activesupport >= 3.0.0
- actions/checkout v3 composite
- ruby/setup-ruby v1 composite
Score: 33.979543169918195