Docs · Billing & Entitlements

Gating a Feature

Using RequireEntitlement to put a resource behind payment.

Putting a resource behind payment is one line: include RequireEntitlement in its controller. Leaving it out is also one line: don't include it. There's no separate configuration file listing which features are paid; the controller itself is the declaration.

Gating a controller

class InvoicesController < ApplicationController
  include RequireEntitlement
  # ...
end

On every action, this checks Billing.for(Current.account).entitled? and redirects to the pricing page when it's false. The example ProjectsController uses exactly this include; copy it as the reference when you scaffold a new paid resource with Adding a Resource.

Who gets through anyway

Admin accounts (User#role == "admin") are exempt from the entitlement check, so an admin can always reach a paid controller regardless of subscription status. This matters for support and for console-driven operations: see Roles and Teams for what admin? covers today.

What this doesn't do

RequireEntitlement answers one question: is this workspace allowed to use the paid surface at all. It says nothing about which specific records the signed-in user can see or modify within that surface; that's Pundit's job, and it applies regardless of whether the feature is paid or free. A controller almost always needs both: include RequireEntitlement at the top, and authorize @record / policy_scope(...) in each action. See Authorization for why these stay separate.

Testing the gate

Add an entitlement-gate test alongside the tenant-isolation test in your request spec: an unsubscribed account hitting a paid controller's action should be redirected to pricing, not shown the feature and not met with an error. The Project resource's request spec is the reference for this assertion.

Next

See how to configure the plan the gate checks against: Stripe Setup.

Common questions

How do I change what a paid plan unlocks in my app?

To gate a feature, add include RequireEntitlement to its controller. To ungate it, delete that line. To change what counts as paid at all, edit the single strategy line in app/models/entitlement.rb. Those are two different decisions and they live in two different places on purpose.

How do I gate a feature behind a paid subscription in Rails?

Add include RequireEntitlement to the controller. Unentitled accounts are redirected to the pricing page with a message; admins are exempt. What "entitled" means is defined separately in app/models/entitlement.rb, so you can change the gate from a subscription to a token balance or to nothing without touching any controller.

How do I remove billing from an app that will be free?

Use the remove-billing skill. It removes the Stripe subscription flow and the mobile in-app purchase path, and leaves authentication, tenancy and the entitlement seam in place. The seam matters: include RequireEntitlement keeps working against an open strategy, so gated controllers are not rewritten and can be gated again later.