There's a lot of open issues
Yaml-backed ApplicationHash for CanCan Roles


~> 11.1.0
~> 3.1.0
~> 5.0
~> 1.2.0
~> 7.0.0
~> 13.0
~> 1.5.0


 Project Readme

Bullet Train Roles

Bullet Train Roles provides a Yaml-based configuration layer on top of CanCanCan. You can use this configuration file to simplify the definition of many common permissions, while still implementing more complicated permissions in CanCanCan's traditional app/model/ability.rb.

Additionally, Bullet Train Roles makes it trivial to assign the same roles and associated permissions at different levels in your application. For example, you can assign someone administrative privileges at a team level, or only at a project level.

Bullet Train Roles was created by Andrew Culver and Adam Pallozzi.

Example Domain Model

For the sake of this document, we're going to assume the following example modeling around users and teams:

  • A User belongs to a Team via a Membership.
  • A User only has one Membership per team.
  • A Membership can have zero, one, or many Roles assigned.
  • A Membership without a Role is just a default team member.

You don't have to name your models the same thing in order to use this Ruby Gem, but it does depend on having a similar structure.

If you're interested in reading more about how and why Bullet Train implements this structure, you can read about it on our blog.


Add these lines to your application's Gemfile:

gem "active_hash", github: "bullet-train-co/active_hash"
gem "bullet_train-roles"

We have to link to a specific downstream version of ActiveHash temporarily while working to merge certain fixes and updates upstream.

And then execute the following in your shell:

bundle install

Finally, run the installation generator:

rails generate bullet_train:roles:install

The installer defaults to installing a configuration for Membership and Team, but it will prompt you so you can specify different models if they differ in your application.

The installer will:

  • stub out a configuration file in config/models/roles.yml.
  • create a database migration to add role_ids:jsonb to Membership.
  • add include Role::Support to app/models/membership.rb.
  • add a basic permit call in app/models/ability.rb.


The provided Role model is backed by a Yaml configuration in config/models/roles.yml.

To help explain this configuration and its options, we'll provide the following hypothetical example:

    Project: read
    Billing::Subscription: read

    - editor
    Project: crud

    - billing
    Billing::Subscription: manage

    - editor
    - billing
    - admin

Here's a breakdown of the structure of the configuration file:

  • default represents all permissions that are granted to any active member on a team.
  • editor, billing, and admin represent additional roles that can be assigned to a membership.
  • models provides a list of resources that members with a specific role will be granted.
  • manageable_roles provides a list of roles that can be assigned to other users by members that have the role being defined.
  • includes provides a list of other roles whose permissions should also be made available to members with the role being defined.
  • manage, read, etc. are all CanCanCan-defined actions that can be granted.

The following things are true given the example configuration above:

  • By default, users on a team are read-only participants.
  • Users with the editor role:
    • can give other users the editor role.
    • can perform crud actions on project (create, read, update and destroy).
    • cannot perform any custom controller actions the projects controller responds to
  • Users with the billing role:
    • can give other users the billing role.
    • can create and update billing subscriptions.
  • Users with the admin role:
    • inherit all the privileges of the editor and billing roles.
    • can give other users the editor, billing, or admin role. (The ability to grant editor and billing privileges is inherited from the other roles listed in includes.)

Assigning Multiple Actions per Resource

You can also grant more granular permissions by supplying a list of the specific actions per resource, like so:

      - read
      - update

Applying Configuration

All of these definitions are interpreted and translated into CanCanCan directives when we invoke the following Bullet Train helper in app/models/ability.rb:

permit user, through: :memberships, parent: :team

In the example above:

  • through should reference a collection on User where access to a resource is granted. The most common example is the memberships association, which grants a User access to a Team. In the context of permit discussions, we refer to the Membership model in this example as "the grant model".
  • parent should indicate which level the models in through will grant a user access at. In the case of a Membership, this is team.

Additional Grant Models

To illustrate the flexibility of this approach, consider that you may want to grant non-administrative team members different permissions for different Project objects on a Team. In that case, permit actually allows us to re-use the same role definitions to assign permissions that are scoped by a specific resource, like this:

permit user, through: :projects_collaborators, parent: :project

In this example, permit is smart enough to only apply the permissions granted by a Projects::Collaborator record at the level of the Project it belongs to. You can turn any model into a grant model by adding include Roles::Support and adding a role_ids:jsonb attribute. You can look at Scaffolding::AbsolutelyAbstract::CreativeConcepts::Collaborator for an example.


If you want to see what CanCanCan directives are being created by your permit calls, you can add the debug: true option to your permit statement in app/models/ability.rb.

Likewise, to see what abilities are being added for a certain user, you can run the following on the Rails console:

user = User.first user, through: :projects_collaborators, parent: :project, debug: true


After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To 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 the created tag, and push the .gem file to


Bug reports and pull requests are welcome on GitHub at This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.


The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the BulletTrain::Roles project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.