Answers · Billing

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.

Two questions, two places

Which surfaces are paid? One line per controller. Adding the include gates it; removing it frees it.

What does paid mean? One line in app/models/entitlement.rb, which returns the strategy: a subscription, a token balance, or nothing.

Keeping them apart is what makes each change cheap. A pricing experiment that moves a feature in or out of the paid tier touches one controller and no billing code. A business model change touches one model and no controllers.

Tiers, if you need more than one

Subscription has a tier enum with free and pro. entitled? ignores it, because the shipped gate is binary: you are in or you are not.

For a real tier split, the honest version is a second question rather than a cleverer version of the first:

Entitlement.for(Current.account).entitled?
Current.account.subscription&.pro?

Resist encoding tiers into RequireEntitlement. The moment the concern knows about plan names, every controller that includes it is coupled to your pricing page, and pricing changes more often than code.

Do not confuse this with authorization

Entitlement asks whether the workspace may use the surface. Pundit asks whether this user may touch this record. A gated controller still needs authorize and policy_scope, and the policies live in app/policies. Skipping the second one means paying customers can read each other's data, which is the worst version of this mistake.

Check both paths

bin/rspec

Every gated controller wants two request specs: entitled gets 200, unentitled is redirected. The example Project slice has both, and copying its spec file is faster than writing them.

Changing a gate on a live app

Adding a gate to a feature people already use locks out existing users at the moment of deploy. Usually worth announcing first, or grandfathering by giving existing accounts an active subscription row before the deploy rather than after the complaints.

Related questions

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.

Can I charge a one-time price instead of a subscription?

Yes. Create a one-time price in Stripe, use payment mode rather than subscription mode in the checkout session, and change what Entitlement.for returns so a completed purchase entitles the account permanently. The gate on each controller does not change, because RequireEntitlement never knew what it was checking.