DOCS LLMs

Pricing plans & entitlements

RailsFast defines what each plan includes with the pricing_plans gem (0.7). Plans live in code, in config/initializers/pricing_plans.rb, and the same definitions drive the pricing page, checkout, Settings, the admin and every feature gate in your app. Connecting plans to Stripe prices is covered in Stripe, payments & plans.

Who owns a plan

The plan owner is the organization. Every signup gets a personal workspace, and the organization is the Stripe customer, so current_organization is what you ask:

current_organization.current_pricing_plan          # the resolved plan
current_organization.plan_allows?(:api_access)     # or plan_allows_api_access?
current_organization.within_plan_limits?(:projects)
current_organization.plan_limit_remaining(:projects)

In controllers, the gem infers the owner from current_organization, so its guards work without configuration:

class Api::BaseController < ApplicationController
  before_action :enforce_api_access!
end

Limits, per-period quotas, model helpers (has_many :projects, limited_by_pricing_plans: ...) and the view helpers are documented in the gem's own guides.

Limits and the grace rule

A limit says what happens when an account goes over it:

plan :starter do
  limits :posts,    to: 20, after_limit: :block_usage
  limits :projects, to: 5,  after_limit: :grace_then_block, grace: 10.days
end

grace: belongs only on an after_limit: :grace_then_block limit, and must be a positive duration of at least one second. The app refuses to boot with PricingPlans::ConfigurationError when it finds grace: on a :block_usage or :just_warn limit (even grace: nil or grace: false), or on a limit with no after_limit:, which means :block_usage. The error names the limit. Run bin/rails runner true after editing the file to catch it before a deploy does.

Changing what an account gets

Plans are configuration. Exceptions for one account are data, and there are four kinds. Every plan_allows? gate honours all of them with no code change. feature_entitlement_source(:feature) tells you where a feature came from: :plan, :grandfather, :grant or nil. An override reports :plan (it changes the plan itself), and a pass reports :grant.

Overrides put one account on a different plan, outside billing:

organization.override_pricing_plan!(:pro, source: "customer_success_gift")
organization.clear_pricing_plan_override!

An override outranks any future Stripe subscription, so use it only for deliberate exceptions. The admin's organization page offers the same two actions. The old assign_pricing_plan! and remove_pricing_plan! still work with a deprecation warning and disappear in pricing_plans 0.8.

Grandfathering keeps a feature you moved to a higher plan for the accounts that subscribed before a cutoff. It is one line in the plan, with no table and no backfill:

plan :starter do
  grandfather :priority_support, subscribed_before: "2026-01-01"
end

Feature grants give one account a feature outside its plan: a comp, beta access, a promise from sales. A revoked grant stays as history:

organization.grant_feature!(:api_access, source: "support", note: "beta tester")
organization.revoke_feature!(:api_access, note: "beta over")

Feature passes are grants for a trial. issue_feature_pass! never replaces a grant the account already has (it raises instead), and a pass can expire, carry named capacity limits and meter a cumulative allowance:

organization.issue_feature_pass!(:api_access, source: "sales", expires_at: 30.days.from_now, usage_limit: 1_000)

Existing boolean gates recognise a pass, but they do not enforce its allowance: plan_allows? neither spends usage_limit nor refuses an exhausted pass. Wrap each operation that consumes the feature in with_feature_access!, which checks and spends the allowance under a lock, and supply capacity measurements through the usage: callable:

organization.with_feature_access!(:api_access, amount: 1) do
  # the call the pass pays for
end

The gem's docs/08-feature-passes.md covers named capacity limits and the usage: callable.

Grants and passes live in the pricing_plans_feature_grants table, which the template creates with three migrations of its own. Do not run rails generate pricing_plans:grants or pricing_plans:passes, even though the gem's error messages suggest them: bin/rails db:migrate is all you need.

In the admin

The admin's Plans section lists overrides, grants, usage and limit states. Overrides and grants are read-only there on purpose: overrides change only through the organization page's actions, and grants only through the owner methods above, which lock the account, validate pass limits and keep the history.

Billing states the gates understand

A past_due subscription keeps its plan while Stripe retries the payment, and reading an account's plan never creates a Stripe customer. See When a renewal payment fails.

Learn more

  • The template's docs/pricing-plan-overrides.md: overrides in depth, the audit task for apps that started on a beta, and the 0.5 to 0.7 upgrade (grace rule, migrations, billing changes).
  • The gem's guides on repricing and grandfathering and feature passes.
  • Pricing page for how the plans render.