{"id":16701678,"url":"https://github.com/coryodaniel/regulator","last_synced_at":"2026-03-02T18:41:01.614Z","repository":{"id":35284514,"uuid":"39545399","full_name":"coryodaniel/regulator","owner":"coryodaniel","description":"Controller-based minimal authorization through OO design and pure Ruby classes","archived":false,"fork":false,"pushed_at":"2019-11-13T09:59:47.000Z","size":172,"stargazers_count":15,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-18T04:42:49.286Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coryodaniel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-23T04:20:12.000Z","updated_at":"2017-11-12T20:42:52.000Z","dependencies_parsed_at":"2022-09-13T17:51:47.369Z","dependency_job_id":null,"html_url":"https://github.com/coryodaniel/regulator","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coryodaniel%2Fregulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coryodaniel%2Fregulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coryodaniel%2Fregulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coryodaniel%2Fregulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coryodaniel","download_url":"https://codeload.github.com/coryodaniel/regulator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244855721,"owners_count":20521694,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-12T18:45:09.390Z","updated_at":"2026-03-02T18:40:56.558Z","avatar_url":"https://github.com/coryodaniel.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Regulator\n[![Build Status](https://travis-ci.org/coryodaniel/regulator.svg)](https://travis-ci.org/coryodaniel/regulator)\n[![Code Climate](https://codeclimate.com/github/coryodaniel/regulator/badges/gpa.svg)](https://codeclimate.com/github/coryodaniel/regulator)\n[![Test Coverage](https://codeclimate.com/github/coryodaniel/regulator/badges/coverage.svg)](https://codeclimate.com/github/coryodaniel/regulator/coverage)\n\nRegulator is a clone of the [Pundit](https://github.com/elabs/pundit) gem and provides a pundit compatible DSL that has **controller namespaced** authorization polices instead of *model namespaced*.\n\nIt uses Ruby classes and object oriented design patterns to build a simple, robust and scaleable authorization system.\n\nExisting pundit policies can be used, although they will have to be namespaced properly, or have the controller accessing set ```Controller.policy_class``` or ```Controller.policy_namespace```\n\nI built this because I believe authorization should be controller-based, not model based, but really enjoyed using the Pundit DSL and I was over [monkey-patching](https://gist.github.com/Systho/3d7632b5aa999cf88d87) pundit in all of my projects to make it work the way I want.\n\nWhy not contribute to pundit? [It's](https://github.com/elabs/pundit/issues/12) [been](https://github.com/elabs/pundit/issues/178) an [on going](https://github.com/elabs/pundit/search?q=namespace\u0026type=Issues\u0026utf8=%E2%9C%93) 'issue' in pundit and it doesn't look [like it'll be reality.](https://github.com/elabs/pundit/pull/190#issuecomment-53052356)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'regulator'\n```\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install regulator\n\nInclude Regulator in your application controller:\n\n``` ruby\nclass ApplicationController \u003c ActionController::Base\n  include Regulator\n  protect_from_forgery\nend\n```\n\n## Generators\n\nInstall regulator\n``` sh\n  rails g regulator:install\n```\n\nCreate a new policy and policy test/spec\n``` sh\n  rails g regulator:policy User\n```\n\nRegulator comes with a generator for creating an ActiveAdmin adapter\n``` sh\n  rails g regulator:activeadmin\n```\n\nThis will create an adapter in your ```lib``` folder.\n\nBe sure to set the following in your ActiveAdmin initializer:\n```ruby\nconfig.authorization_adapter = \"ActiveAdmin::RegulatorAdapter\"\n\n# Optional\n# Sets a scope for all ActiveAdmin polices to exist in\n#\n# Example\n# app/policies/admin_policies/user_policy.rb #=\u003e AdminPolicies::UserPolicy\n#\n# config.regulator_policy_namespace = \"AdminPolicies\"\nconfig.regulator_policy_namespace = nil\n\n# Optional\n# Sets the default policy to use if no policy is found\n#\n# config.regulator_default_policy = BlackListPolicy\nconfig.regulator_default_policy = nil\n```\n\n## Policies\n\nRegulator is focused around the notion of policy classes. We suggest that you put\nthese classes in `app/policies`. This is a simple example that allows updating\na post if the user is an admin, or if the post is unpublished:\n\n``` ruby\nclass PostPolicy\n  attr_reader :user, :post\n\n  def initialize(user, post)\n    @user = user\n    @post = post\n  end\n\n  def update?\n    user.admin? or not post.published?\n  end\nend\n```\n\nRegulator makes the following assumptions about this class:\n\n- The class has the name `Scope` and is nested under the policy class.\n- The first argument is a user. In your controller, Regulator will call the\n  `current_user` method to retrieve what to send into this argument.\n- The second argument is a scope of some kind on which to perform some kind of\n  query. It will usually be an ActiveRecord class or a\n  `ActiveRecord::Relation`, but it could be something else entirely.\n- Instances of this class respond to the method `resolve`, which should return\n  some kind of result which can be iterated over. For ActiveRecord classes,\n  this would usually be an `ActiveRecord::Relation`.\n\nYou'll probably want to inherit from the application policy scope generated by the\ngenerator, or create your own base class to inherit from:\n\n``` ruby\nclass PostPolicy \u003c ApplicationPolicy\n  class Scope \u003c Scope\n    def resolve\n      if user.admin?\n        scope.all\n      else\n        scope.where(:published =\u003e true)\n      end\n    end\n  end\n\n  def update?\n    user.admin? or not post.published?\n  end\nend\n```\n\nYou can now use this class from your controller via the `policy_scope` method:\n\n``` ruby\ndef index\n  @posts = policy_scope(Post)\nend\n```\n\nJust as with your policy, this will automatically infer that you want to use\nthe `PostPolicy::Scope` class, it will instantiate this class and call\n`resolve` on the instance. In this case it is a shortcut for doing:\n\n``` ruby\ndef index\n  @posts = PostPolicy::Scope.new(current_user, Post).resolve\nend\n```\n\nYou can, and are encouraged to, use this method in views:\n\n``` erb\n\u003c% policy_scope(@user.posts).each do |post| %\u003e\n  \u003cp\u003e\u003c%= link_to post.title, post_path(post) %\u003e\u003c/p\u003e\n\u003c% end %\u003e\n```\n\n## Manually specifying policy classes\n\nSometimes you might want to explicitly declare which policy to use for a given\nclass, instead of letting Regulator infer it. This can be done like so:\n\nRegulator supports the Pundit-style model \"policy_class\", but also implements it\nat the controller level. You can also set a controller's policy_namespace if you want to use an alternate namespace to the one the controller is in.\n\n\n``` ruby\n# Model level\nclass Post\n  def self.policy_class\n    PostablePolicy\n  end\nend\n```\n\n``` ruby\n# Controller level\nclass Api::Post\n  # By default, Regulator will look for Api::PostPolicy\n  def self.policy_class\n    PostPolicy\n  end\nend\n```\n\n``` ruby\n# Here the admin namespace could be told to use the same policy as the API namespace\nclass Admin::Post\n  # By default, Regulator will look for Admin::PostPolicy\n  def self.policy_class\n    PostPolicy\n  end\n\n  # You can also set it at the instance level\n  def policy_class\n    if current_user.is_a_high_paying_member?\n      HighClassPostPolicy\n    else\n      LowClassPostPolicy\n    end\n  end\nend\n```\n\n``` ruby\nclass Admin::Comment\n  def self.policy_namespace\n    # Will make regulator look for ActiveAdmin::CommentPolicy instead of\n    # Admin::CommentPolicy\n    ActiveAdmin\n  end\nend\n```\n\nOf course ```policy_namespace``` and ```policy_class``` can be used together.\n\n## Policy Namespaces\n\nThis table explains what policies Regulator will look for in different scenarios:\n\n| Controller Name                                        | Model Name       | Expected Policy                |\n| -------------------------------------------------------|------------------| -------------------------------|\n| AlbumController                                        | Album            |  AlbumPolicy                   |\n| Api::AlbumController                                   | Album            |  Api::AlbumPolicy              |\n| Admin::AlbumController                                 | Album            |  Admin::AlbumPolicy            |\n| Admin::AlbumController.policy_namespace = 'SuperUser'  | Album            |  SuperUser::AlbumPolicy        |\n| Admin::AlbumController.policy_namespace = nil          | Album            |  AlbumPolicy                   |\n| Admin::AlbumContoller                                  | MySongGem::Album |  Admin::MySongGem::AlbumPolicy |\n| SongController#policy_class = TrackPolicy              | Song             |  TrackPolicy                   |\n| SongController.policy_class = Legacy::TrackPolicy      | Song             |  Legacy::TrackPolicy           |\n\n```policy_class``` at the controller-level is king. Setting it will override all logic for determining the policy to use.\n\n## ActiveAdmin Auth Adapter\n\nThere is a generator and an included adapter. Using the generator will place a more complex customizable adapter in your ```lib``` directory.\n\nA simple adapter is also provided, to use add the following to your active_admin initializer:\n``` ruby\nActiveAdmin::Dependency.regulator!\n\nrequire 'regulator'\nrequire 'regulator/active_admin_adapter'\nActiveAdmin.setup do |config|\n  config.authorization_adapter = \"Regulator::ActiveAdminAdapter\"\n  ...\n```\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n## Contributors\n  * [Cory O'Daniel](http://linkedin.com/in/coryodaniel)\n  * All the hard work done on [Pundit](https://github.com/elabs/pundit)\n\n  Thanks to Warren G for the inspiration, bro.\n\n  ![Regulator](https://upload.wikimedia.org/wikipedia/commons/a/ac/Nat_Powers_%26_Warren_G.jpg)\n\n## TODOs\n  * [ ] documentation\n    * [ ] yard doc\n    * [ ] Lotus examples\n    * [ ] Grape examples\n    * [ ] ROM examples\n    * [ ] Custom permissions examples\n    * [ ] RoleModel gem examples\n    * [ ] rolify gem examples\n  * [ ] contributing wiki\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoryodaniel%2Fregulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoryodaniel%2Fregulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoryodaniel%2Fregulator/lists"}