### Model Setup with PlanOwner Mixin and Usage Examples Source: https://context7.com/rameerez/pricing_plans/llms.txt Demonstrates how to integrate the `PricingPlans::PlanOwner` mixin into a Rails model (e.g., `Organization`) to manage pricing plan associations. Includes examples of checking the current plan, feature access, and limit status. ```ruby # app/models/organization.rb class Organization < ApplicationRecord include PricingPlans::PlanOwner # Link associations to pricing plan limits has_many :projects, limited_by_pricing_plans: { error_after_limit: "Project limit reached!" }, dependent: :destroy has_many :team_memberships, limited_by_pricing_plans: { limit_key: :team_members }, dependent: :destroy has_many :exports, limited_by_pricing_plans: { limit_key: :exports, per: :calendar_month } end # Usage examples org = Organization.find(1) # Check current plan org.current_pricing_plan # => # org.on_free_plan? # => false # Feature checks org.plan_allows?(:api_access) # => true org.plan_allows_premium_features? # => true (dynamic method) # Limit checks org.within_plan_limits?(:projects) # => true org.within_plan_limits?(:projects, by: 5) # => false (check if 5 more allowed) org.plan_limit_remaining(:projects) # => 12 org.plan_limit_percent_used(:projects) # => 52.0 ``` -------------------------------- ### Admin Dashboard Example using Scopes Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md An example controller action showing how to use the admin scopes to count organizations in different limit states for a dashboard. ```ruby # app/controllers/admin/dashboard_controller.rb def show @orgs_needing_attention = Organization.needing_attention.count @orgs_in_grace = Organization.in_grace_period.count @orgs_blocked = Organization.with_blocked_limits.count @orgs_healthy = Organization.within_all_limits.count end ``` -------------------------------- ### Setup Development Environment - Bash Source: https://github.com/rameerez/pricing_plans/blob/main/README.md Command to set up the development environment for the pricing_plans gem after checking out the repository. This installs necessary dependencies. ```bash bin/setup ``` -------------------------------- ### Install Pricing Plans Gem Source: https://context7.com/rameerez/pricing_plans/llms.txt Instructions for installing the pricing_plans gem in a Rails application. This involves adding the gem to the Gemfile, running bundle install, generating the initializer, and migrating the database. ```ruby # Add to Gemfile gem "pricing_plans" ``` ```bash bundle install rails g pricing_plans:install rails db:migrate ``` -------------------------------- ### Configure Limit Behavior After Reaching Cap Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This example shows how to configure the behavior when a limit is reached using the `after_limit` option. It demonstrates setting the behavior to `:just_warn`, which logs a warning but does not block usage. ```ruby # Just warn (never block): PricingPlans.configure do |config| plan :free do price 0 allows :api_access limits :projects, to: 3, after_limit: :just_warn end end ``` -------------------------------- ### Install and Configure pricing_plans Gem (Bash) Source: https://github.com/rameerez/pricing_plans/blob/main/README.md These commands outline the process of adding the pricing_plans gem to a Rails application, installing it, generating necessary configuration files and migrations, and running the migrations to set up the database. ```bash gem "pricing_plans" bundle install rails g pricing_plans:install rails db:migrate ``` -------------------------------- ### Register Wildcard Callback for All Limits in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This example shows how to register a single callback that fires for any limit warning across all resources. It's useful for centralized logging or analytics, such as tracking limit warnings universally. ```ruby # Fires for ANY limit warning (projects, licenses, api_calls, etc.) config.on_warning do |plan_owner, limit_key, threshold| Analytics.track(plan_owner, "limit_warning", limit: limit_key, threshold: threshold) end ``` -------------------------------- ### Install Gem Locally - Bash Source: https://github.com/rameerez/pricing_plans/blob/main/README.md Command to install the pricing_plans gem onto your local machine. This is typically done after making changes or for local development. ```bash bundle exec rake install ``` -------------------------------- ### Example: Usage Resets Next Period (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md Demonstrates how usage limits reset automatically at the beginning of a new billing period. It shows assigning a plan, creating resources within a period, checking remaining limits, and verifying grace periods. It then advances to the next period to show the reset. ```ruby # pro allows 3 custom models per month PricingPlans::Assignment.assign_plan_to(org, :pro) travel_to(Time.parse("2025-01-15 12:00:00 UTC")) do 3.times { org.custom_models.create!(name: "Model") } PricingPlans::LimitChecker.plan_limit_remaining(org, :custom_models) # => 0 result = PricingPlans::ControllerGuards.require_plan_limit!(:custom_models, plan_owner: org) result.grace? # => true when after_limit: :grace_then_block end travel_to(Time.parse("2025-02-01 12:00:00 UTC")) do # New window — counters reset automatically PricingPlans::LimitChecker.plan_limit_remaining(org, :custom_models) # => 3 end ``` -------------------------------- ### Define an Enterprise Plan in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md Illustrates how to define an enterprise plan, often used alongside free and paid plans. This example sets a `price_string` to 'Contact' and provides custom details like 'Dedicated SLAs' and a mailto link for sales inquiries. ```ruby # Your free plan here # Then your paid plans here, linked to Stripe IDs # And finally, an enterprise plan: plan :enterprise do price_string "Contact" description "Get in touch and we'll fit your needs." bullets "Custom limits", "Dedicated SLAs", "Dedicated support" cta_text "Contact us" cta_url "mailto:sales@example.com" unlimited :products allows :api_access, :premium_features end ``` -------------------------------- ### Configure Multiple Warning Thresholds in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This example shows how to configure multiple warning thresholds for a resource, such as projects. It defines thresholds at 60%, 80%, and 95% usage, ensuring notifications are sent at each stage before the limit is fully reached. ```ruby limits :projects, to: 100, warn_at: [0.6, 0.8, 0.95] # Fires at 60%, 80%, and 95% usage ``` -------------------------------- ### Get Limits Overview Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md Get a summary of all limits, including an overall severity status and helper fields for displaying plan usage. This is a convenient endpoint for a quick overview of the user's plan status. ```APIDOC ## GET /user/limits_overview ### Description Provides a summary of all limits, including an overall severity and helper fields for displaying plan usage. ### Method GET ### Endpoint `/user/limits_overview` ### Parameters #### Query Parameters - **keys** (array of strings) - Optional - A list of specific limit keys to include in the overview (e.g., `?keys[]=projects&keys[]=posts`). ### Response #### Success Response (200) - **severity** (string) - The highest severity level among all limits. - **severity_level** (integer) - The numerical representation of the highest severity level. - **title** (string) - An overall title summarizing the plan status. - **message** (string) - A user-friendly message for the overall plan status. - **attention?** (boolean) - Indicates if any limits require user attention. - **keys** (array of strings) - An array of all computed limit keys. - **highest_keys** (array of strings) - An array of limit keys with the highest severity. - **highest_limits** (array of StatusItem) - An array of `StatusItem` objects for limits with the highest severity. - **keys_sentence** (string) - A human-readable sentence listing limit keys that require attention. - **noun** (string) - The noun used in the context of plan limits (e.g., "plan limit"). - **has_have** (string) - Grammatical indicator ('has' or 'have'). - **cta_text** (string) - Call to action text for upgrading or managing the plan. - **cta_url** (string) - URL for the call to action. #### Response Example ```json { "severity": ":at_limit", "severity_level": 2, "title": "At your plan limit", "message": "You have reached your plan limit for products.", "attention?": true, "keys": [":products", ":licenses", ":activations"], "highest_keys": [":products"], "highest_limits": [ { "key": ":projects", "human_key": "projects", "current": 1, "allowed": 1, "percent_used": 100.0, "severity": ":at_limit", "severity_level": 2, "message": "You’ve reached your limit for projects (1/1). Upgrade your plan to unlock more.", "remaining": 0 } ], "keys_sentence": "products", "noun": "plan limit", "has_have": "has", "cta_text": "View Plans", "cta_url": null } ``` ``` -------------------------------- ### Grace Period Then Block Usage After Limit Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This example configures the `after_limit` behavior to `:grace_then_block`. This allows a grace period after the limit is reached before usage is blocked, providing a smoother user experience. The grace period duration can also be specified. ```ruby # Opt into grace, then block: PricingPlans.configure do |config| plan :free do price 0 allows :api_access limits :projects, to: 3, after_limit: :grace_then_block end end ``` -------------------------------- ### Get Overview of All User Limits Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md Provides a summarized view of all user limits, including overall severity, titles, messages, and attention indicators. It returns a JSON object with helper fields for displaying plan usage status. ```ruby user.limits_overview user.limits_overview(:projects, :posts) ``` -------------------------------- ### Gate Features in a Pricing Plan Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This example demonstrates how to allow specific features for a pricing plan. The `allows` method is used within the plan definition to grant access to features like `:api_access`. Features are disabled by default. ```ruby PricingPlans.configure do |config| plan :free do price 0 allows :api_access end end ``` -------------------------------- ### Handle Grace Period Start Callbacks in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This snippet sets up a callback that triggers when a limit is exceeded and the grace period begins. It shows how to send an email informing the user about the exceeded limit and the duration of the grace period. ```ruby config.on_grace_start(:licenses) do |plan_owner, limit_key, grace_ends_at| GracePeriodMailer.limit_exceeded(plan_owner, limit_key, grace_ends_at).deliver_later end ``` -------------------------------- ### Interactive Console - Bash Source: https://github.com/rameerez/pricing_plans/blob/main/README.md Command to start an interactive Ruby console for experimenting with the pricing_plans gem. This is useful for debugging and exploring the gem's functionality. ```bash bin/console ``` -------------------------------- ### Plan Comparison Ergonomics (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/docs/05-semantic-pricing.md Offers methods for comparing a given plan against the current plan, determining upgrade/downgrade possibilities, and retrieving reasons for blocked downgrades. These are useful for guiding user actions in pricing UIs. ```ruby plan.current_for?(current_plan) # boolean plan.upgrade_from?(current_plan) # boolean plan.downgrade_from?(current_plan) # boolean plan.downgrade_blocked_reason(from: current_plan, plan_owner: org) # string | nil ``` -------------------------------- ### Get Status of All Limits Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md Retrieve the status of all limits for the authenticated user. This endpoint returns an array of StatusItem objects, providing a comprehensive overview of the user's plan limits. ```APIDOC ## GET /user/limits ### Description Retrieves the current status of all limits for the authenticated user. ### Method GET ### Endpoint `/user/limits` ### Parameters #### Query Parameters - **keys** (array of strings) - Optional - A list of specific limit keys to retrieve status for (e.g., `?keys[]=projects&keys[]=posts`). ### Response #### Success Response (200) - Returns an array of `StatusItem` objects, each containing detailed information about a specific limit (see `GET /user/limit/:key` for `StatusItem` structure). #### Response Example ```json [ { "key": ":limit_1", "human_key": "Limit 1", "current": 5, "allowed": 10, "percent_used": 50.0, "severity": ":ok", "severity_level": 0, "message": null, "remaining": 5 }, { "key": ":limit_2", "human_key": "Limit 2", "current": 9, "allowed": 10, "percent_used": 90.0, "severity": ":warning", "severity_level": 1, "message": "You have used 9/10 Limit 2.", "remaining": 1 } ] ``` ``` -------------------------------- ### Attach Metadata to Pricing Plans (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/README.md This example demonstrates how to attach arbitrary metadata, such as icons and color codes, directly to a pricing plan definition within the initializer. This metadata can then be used for UI presentation purposes. ```ruby plan :hobby do metadata icon: "rocket", color: "bg-red-500" end plan.metadata[:icon] # => "rocket" ``` -------------------------------- ### Enforce Limits in a Pricing Plan Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This code defines a limit for a specific resource within a pricing plan. The `limits` method is used to set a maximum number of resources (e.g., `:projects`) allowed for a plan. This example sets the limit for projects to 3. ```ruby PricingPlans.configure do |config| plan :free do price 0 allows :api_access limits :projects, to: 3 end end ``` -------------------------------- ### Check Feature Access and Remaining Limits (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/README.md This example shows how to directly check a user's plan for API access or determine the remaining number of a specific limit (e.g., projects) anywhere in the application using the methods provided by the pricing_plans gem. ```ruby @user.plan_allows_api_access? # => true / false @user.projects_remaining # => 2 ``` -------------------------------- ### Example of brittle pricing plan enforcement in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/README.md This snippet demonstrates a common, yet brittle, way to enforce pricing plan limits directly in Ruby code. It involves checking the user's subscription plan and a specific feature's count, leading to duplicated logic and potential inconsistencies. ```ruby if user_signed_in? && current_user.payment_processor&.subscription&.processor_plan == "pro" && current_user.projects.count <= 5 # ... elsif user_signed_in? && current_user.payment_processor&.subscription&.processor_plan == "premium" && current_user.projects.count <= 10 # ... end ``` -------------------------------- ### Configure Pricing Plans and Limits in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This snippet demonstrates how to configure pricing plans and set limits for resources like licenses and activations. It shows how to define warning thresholds and specify actions to take when limits are reached, including grace periods and blocking. ```ruby PricingPlans.configure do |config| plan :pro do limits :licenses, to: 100, warn_at: [0.8, 0.95], after_limit: :grace_then_block, grace: 7.days limits :activations, to: 300, warn_at: [0.8, 0.95], after_limit: :grace_then_block, grace: 7.days end end ``` -------------------------------- ### Get Raw Limit Check Result in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/02-controller-helpers.md Demonstrates how to use `require_plan_limit!` to get a raw `Result` object for limit checks. This allows for mid-action enforcement by inspecting the `result` object's properties like `blocked?`, `message`, `ok?`, etc., before proceeding with the action. ```ruby def create result = require_plan_limit!(:products, plan_owner: current_organization, by: 1) if result.blocked? # ok?, warning?, grace?, blocked?, success? # result.message is available: redirect_to pricing_path, alert: result.message, status: :see_other and return end # ... Product.create!(...) redirect_to products_path end ``` -------------------------------- ### Database Index for Performance Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md A recommendation for adding a composite index to the `pricing_plans_enforcement_states` table to improve the performance of limit-related queries on large datasets. ```ruby add_index :pricing_plans_enforcement_states, [:plan_owner_type, :plan_owner_id, :exceeded_at], name: 'index_enforcement_states_on_owner_and_exceeded' ``` -------------------------------- ### Chainable Admin Scopes with ActiveRecord Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md Demonstrates how the provided ActiveRecord scopes can be chained with other ActiveRecord methods for complex queries. ```ruby # Find exceeded organizations created this month Organization.with_exceeded_limits.where(created_at: 1.month.ago..) # Paginate blocked organizations Organization.with_blocked_limits.order(:created_at).limit(10) # Count organizations in grace period Organization.in_grace_period.count ``` -------------------------------- ### Syntactic Sugar for Plan Limits and Grace Helpers Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md This code illustrates the syntactic sugar methods automatically generated for `PlanOwner` models when a `has_many` relationship matches a defined limit key. These methods provide a more concise way to check limits and grace periods. ```ruby # Check limits (per `limits` key) user.projects_remaining user.projects_percent_used user.projects_within_plan_limits? # Grace helpers (per `limits` key) user.projects_grace_active? user.projects_grace_ends_at user.projects_blocked? ``` -------------------------------- ### Gate Features in PlanOwner Class with `plan_allows?` Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md This code demonstrates how to check for feature flag availability using the `plan_allows?` method on the `PlanOwner` class. It also shows the equivalent syntactic sugar method for checking specific features. ```ruby user.plan_allows?(:api_access) # => true/false user.plan_allows_api_access? ``` -------------------------------- ### Get Status of All User Limits Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md Fetches the current status for all defined user limits. This method returns an array of StatusItem objects, providing a comprehensive view of usage across all limits. It can also be filtered to return specific limits. ```ruby user.limits user.limits(:projects, :posts) ``` -------------------------------- ### Use Syntactic Sugar for Limit Enforcement in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/02-controller-helpers.md Demonstrates using generated syntactic sugar methods for enforcing plan limits, such as `enforce_projects_limit!` and `enforce_api_access!`. These methods are created based on `` definitions in `pricing_plans.rb` and can be used with `only` or `except` options in `before_action`. ```ruby before_action :enforce_projects_limit!, only: :create before_action :enforce_api_access! ``` -------------------------------- ### Backward Compatibility for Callback Signatures in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This code demonstrates support for older callback signatures for backward compatibility. While the new signature includes `limit_key`, the old signature without it is still functional. ```ruby # Old signature (still works) config.on_warning(:projects) { |plan_owner, threshold| ... } # New signature (recommended) config.on_warning(:projects) { |plan_owner, limit_key, threshold| ... } ``` -------------------------------- ### Get Detailed Pricing Plan Limit Status in Rails Source: https://context7.com/rameerez/pricing_plans/llms.txt Retrieve detailed status information for pricing plan limits to build UI components. This includes current usage, allowed limits, percentage used, remaining capacity, and severity levels. ```ruby org = Organization.find(1) # Single limit status status = org.limit(:projects) # => # # All limits status statuses = org.limits(:projects, :team_members, :exports) statuses.each do |s| puts "#{s.key}: #{s.current}/#{s.allowed} (#{s.severity})" end # Overall summary with aggregate helpers overview = org.limits_overview(:projects, :team_members) # => { # severity: :warning, # severity_level: 1, # title: "Approaching plan limit", # message: "You are approaching your plan limit for projects.", # attention?: true, # keys: [:projects, :team_members], # highest_keys: [:projects], # keys_sentence: "projects", # noun: "plan limit", # has_have: "has", # cta_text: "View Plans", # cta_url: "/pricing" # } # Convenience methods org.limits_severity(:projects, :exports) # => :warning org.limits_message(:projects, :exports) # => "You are approaching..." org.limit_overage(:projects) # => 0 (within limit) org.attention_required_for_limit?(:projects) # => true org.approaching_limit?(:projects) # => true org.approaching_limit?(:projects, at: 0.9) # => false # Alert data for UI components alert = org.limit_alert(:projects) # => { # visible?: true, # severity: :warning, # title: "Approaching Limit", # message: "You're getting close to your limit...", # overage: 0, # cta_text: "View Plans", # cta_url: "/pricing" # } # CTA helper org.plan_cta # => { text: "Upgrade to Pro", url: "/pricing" } ``` -------------------------------- ### Define Per-Period Allowances for Limits Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This snippet shows how to define limits that reset periodically, such as monthly. The `per:` option is used with values like `:calendar_month`, `:calendar_week`, or `:calendar_day` to specify the reset window. This example allows up to 3 custom models per calendar month. ```ruby plan :pro do # Allow up to 3 custom models per calendar month limits :custom_models, to: 3, per: :calendar_month end ``` -------------------------------- ### Combine Specific and Wildcard Callbacks in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This snippet illustrates how to use both specific and wildcard callbacks. It first defines a specific callback for project limit warnings to send targeted emails, followed by a wildcard callback to log all limit warnings to analytics. ```ruby # Specific: send targeted email for projects config.on_warning(:projects) do |plan_owner, limit_key, threshold| ProjectLimitMailer.warning(plan_owner, threshold).deliver_later end # Wildcard: log all warnings to analytics config.on_warning do |plan_owner, limit_key, threshold| Analytics.track(plan_owner, "limit_warning", limit: limit_key, threshold: threshold) end ``` -------------------------------- ### Enforce API Access in Controllers (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/README.md This example shows how to use a `before_action` filter in a Rails controller to enforce a specific feature, such as API access, using the pricing_plans gem. This ensures that only users with the appropriate plan can access certain controller actions. ```ruby before_action :enforce_api_access!, only: [:create] ``` -------------------------------- ### Handle Usage Warning Callbacks in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This code configures a callback that fires when usage crosses a warning threshold (e.g., 80% or 95% of a limit). It demonstrates sending an email notification to the plan owner using a mailer. ```ruby config.on_warning(:licenses) do |plan_owner, limit_key, threshold| UsageWarningMailer.approaching_limit(plan_owner, limit_key, threshold).deliver_later end ``` -------------------------------- ### Define Model Associations with Limits (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/README.md This example shows how to define a `has_many` association in a Rails model, incorporating pricing plan limits for the associated records. It uses the `limited_by_pricing_plans` option to enforce a limit on the number of projects a user can have, with a custom error message. ```ruby class User < ApplicationRecord include PricingPlans::PlanOwner has_many :projects, limited_by_pricing_plans: { error_after_limit: "Too many projects for your plan!" }, dependent: :destroy end ``` -------------------------------- ### Configure Pricing Plans with Included Credits (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/docs/06-gem-compatibility.md Demonstrates how to configure pricing plans to include cosmetic credit information for UI display. The `includes_credits` method sets the number of credits a plan offers, which is purely for presentation in pricing tables. The actual credit management and fulfillment remain the responsibility of the `usage_credits` gem. ```ruby PricingPlans.configure do |config| config.plan :free do price 0 includes_credits 100 end config.plan :pro do price 29 includes_credits 5_000 end end ``` -------------------------------- ### Configure Global Redirect on Blocked Limit in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/02-controller-helpers.md Configures a global default redirect path or URL when a plan limit is reached and blocks an action. This is set in an initializer file (`config/initializers/pricing_plans.rb`) using `PricingPlans.configure` and can accept a symbol, string, or a Proc. ```ruby # config/initializers/pricing_plans.rb PricingPlans.configure do |config| config.redirect_on_blocked_limit = :pricing_path # or "/pricing" or ->(result) { pricing_path } end ``` -------------------------------- ### Report Overage with Message - Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/README.md Generates an overage report for a given organization and plan, including a human-readable message. It returns an object containing items with details about limits, current usage, and grace periods. This can be used to inform users about their overages and guide remediation. ```ruby report = PricingPlans::OverageReporter.report_with_message(org, :free) if report.items.any? flash[:alert] = report.message # report.items -> [#] end ``` -------------------------------- ### Handle Block Callbacks in Ruby Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This code configures a callback that executes when the grace period expires and the user is blocked from further usage. It demonstrates sending an email notification about the blocked access and the need to upgrade. ```ruby config.on_block(:licenses) do |plan_owner, limit_key| BlockedMailer.access_blocked(plan_owner, limit_key).deliver_later end ``` -------------------------------- ### Run Minitest Suite - Bash Source: https://github.com/rameerez/pricing_plans/blob/main/README.md Command to execute the test suite for the pricing_plans gem using Minitest. This is typically run after setting up the development environment to ensure code integrity. ```bash bundle exec rake test ``` -------------------------------- ### Generate UI Data and Call-to-Action (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/docs/05-semantic-pricing.md Provides ActionView helpers to generate data structures for pricing UI elements and call-to-action buttons. These helpers simplify the integration of pricing information into web interfaces. ```ruby pricing_plan_ui_data(plan) # => { # monthly_price:, yearly_price:, # monthly_price_cents:, yearly_price_cents:, # monthly_price_id:, yearly_price_id:, # free:, label: # } pricing_plan_cta(plan, plan_owner: nil, context: :marketing, current_plan: nil) # => { text:, url:, method: :get, disabled:, reason: } ``` -------------------------------- ### Configure Pricing Semantics and Policies (Ruby) Source: https://github.com/rameerez/pricing_plans/blob/main/docs/05-semantic-pricing.md Allows comprehensive configuration of pricing semantics, including default currency symbols, caching behavior, custom price resolution, free price captions, default UI intervals, and downgrade policies. This enables tailoring the gem to specific application needs. ```ruby PricingPlans.configure do |config| # Currency symbol when Stripe is absent config.default_currency_symbol = "$" # Cache & TTL for Stripe Price lookups config.price_cache = Rails.cache config.price_cache_ttl = 10.minutes # Optional hook to fully customize components # Signature: ->(plan, interval) { PricingPlans::PriceComponents | nil } config.price_components_resolver = ->(plan, interval) { nil } # Optional free copy used by some data helpers config.free_price_caption = "Forever free" # Default UI interval for toggles config.interval_default_for_ui = :month # or :year # Downgrade policy used by CTA ergonomics # Signature: ->(from:, to:, plan_owner:) { [allowed_boolean, reason_or_nil] } config.downgrade_policy = ->(from:, to:, plan_owner:) { [true, nil] } end ``` -------------------------------- ### Display All Pricing Plans in ERB Source: https://github.com/rameerez/pricing_plans/blob/main/docs/04-views.md Iterates through all available pricing plans and displays their details, including name, description, features, price, and call-to-action. This snippet is useful for building dynamic pricing tables. It uses the `PricingPlans.plans` method to retrieve plan data. ```erb <% PricingPlans.plans.each do |plan| %>

<%= plan.name %>

<%= plan.description %>

    <% plan.bullets.each do |b| %>
  • <%= b %>
  • <% end %>
<%= plan.price_label %>
<% if (url = plan.cta_url) %> <%= link_to plan.cta_text, url, class: 'btn' %> <% else %> <%= button_tag plan.cta_text, class: 'btn', disabled: true %> <% end %>
<% end %> ``` -------------------------------- ### Enforce Limits in PlanOwner Class with Helper Methods Source: https://github.com/rameerez/pricing_plans/blob/main/docs/03-model-helpers.md This snippet lists various helper methods available on the `PlanOwner` class for checking plan limits and grace periods. These methods allow you to query remaining limits, percentage used, grace period status, and whether actions are blocked due to exceeding limits. ```ruby # Check limits for a relationship user.plan_limit_remaining(:projects) # => integer or :unlimited user.plan_limit_percent_used(:projects) # => Float percent user.within_plan_limits?(:projects, by: 1) # => true/false # Grace helpers user.grace_active_for?(:projects) # => true/false user.grace_ends_at_for(:projects) # => Time or nil user.grace_remaining_seconds_for(:projects) # => Integer seconds user.grace_remaining_days_for(:projects) # => Integer days (ceil) user.plan_blocked_for?(:projects) # => true/false (considering after_limit policy) ``` -------------------------------- ### Define a Free Pricing Plan Source: https://github.com/rameerez/pricing_plans/blob/main/docs/01-define-pricing-plans.md This snippet shows the basic structure for defining a free pricing plan. It sets the price to 0 and marks it as the default plan using the `default!` method within the `PricingPlans.configure` block. ```ruby PricingPlans.configure do |config| plan :free do price 0 default! end end ``` -------------------------------- ### Configure Pricing Plans with DSL Source: https://context7.com/rameerez/pricing_plans/llms.txt Defines various pricing plans using the pricing_plans gem's DSL within an initializer. It covers plan attributes like price, name, description, features (allows/disallows), limits (persistent and per-period), and UI-related metadata. It also shows how to configure callbacks for limit events and global settings. ```ruby # config/initializers/pricing_plans.rb PricingPlans.configure do |config| # Default plan for new users plan :free do price 0 default! name "Free Plan" description "Get started for free" bullets "Up to 3 projects", "Basic features", "Community support" metadata icon: "rocket", color: "bg-gray-500" allows :basic_features disallows :api_access # Cosmetic; features blocked by default limits :projects, to: 3 limits :team_members, to: 1 end # Paid plan with Stripe integration plan :pro do stripe_price month: "price_abc123", year: "price_def456" highlighted! # Mark as popular/recommended name "Pro Plan" description "For growing teams" bullets "Up to 25 projects", "API access", "Priority support" metadata icon: "zap", color: "bg-blue-500" cta_text "Upgrade to Pro" cta_url "/pricing" allows :api_access, :premium_features limits :projects, to: 25, warn_at: [0.8, 0.95], after_limit: :grace_then_block, grace: 7.days limits :team_members, to: 10 limits :exports, to: 50, per: :calendar_month # Per-period allowance unlimited :api_calls end # Enterprise plan with custom pricing plan :enterprise do price_string "Contact" name "Enterprise" description "Custom solutions for large teams" bullets "Unlimited everything", "Dedicated support", "Custom SLAs" cta_text "Contact Sales" cta_url "mailto:sales@example.com" allows :api_access, :premium_features, :enterprise_features unlimited :projects, :team_members, :exports end # Hidden plan for grandfathered users plan :legacy_2023 do price 15 hidden! # Won't appear on pricing page limits :projects, to: 100 allows :api_access end # Callbacks for lifecycle events config.on_warning(:projects) do |plan_owner, limit_key, threshold| UsageMailer.approaching_limit(plan_owner, limit_key, threshold).deliver_later end config.on_grace_start(:projects) do |plan_owner, limit_key, grace_ends_at| GraceMailer.limit_exceeded(plan_owner, limit_key, grace_ends_at).deliver_later end config.on_block(:projects) do |plan_owner, limit_key| BlockedMailer.access_blocked(plan_owner, limit_key).deliver_later end # Global settings config.controller_plan_owner :current_organization config.redirect_on_blocked_limit = :pricing_path config.default_cta_text = "View Plans" config.default_cta_url = "/pricing" end ``` -------------------------------- ### Render Pricing Tables and Conditional UI with ERB Helpers Source: https://context7.com/rameerez/pricing_plans/llms.txt This ERB code snippet demonstrates how to render a dynamic pricing table using plan data. It includes conditional highlighting, displaying plan details, features, and call-to-action buttons. It also shows how to implement conditional UI elements based on plan limits and display usage meters and alert banners. ```erb <%# app/views/pricing/index.html.erb %>
<% PricingPlans.plans.each do |plan| %>
<% if plan.metadata[:icon] %> <%= plan.metadata[:icon] %> <% end %>

<%= plan.name %>

<%= plan.description %>

<%= plan.price_label %>
    <% plan.bullets.each do |bullet| %>
  • <%= bullet %>
  • <% end %>
<% if (url = plan.cta_url) %> <%= link_to plan.cta_text, url, class: "btn" %> <% else %> <% end %>
<% end %>
<%# Conditional UI based on limits %> <% if current_organization.within_plan_limits?(:projects) %> <%= link_to "New Project", new_project_path, class: "btn btn-primary" %> <% else %>

<%= current_organization.limit(:projects).message %>

<% end %> <%# Usage meter component %> <% status = current_organization.limit(:projects) %>
Projects: <%= status.current %>/<%= status.allowed %>
"> <%= status.message %>

<% end %>
<%# Alert banner %> <% if current_organization.attention_required_for_limit?(:projects) %> <% alert = current_organization.limit_alert(:projects) %>
<%= alert[:title] %>

<%= alert[:message] %>

<%= link_to alert[:cta_text], alert[:cta_url], class: "btn" %>
<% end %> ``` -------------------------------- ### Alerts and Usage: Display Plan Usage Summary in ERB Source: https://github.com/rameerez/pricing_plans/blob/main/docs/04-views.md Displays a summary of the current plan's usage for a specific limit, showing current usage, allowed amount, and percentage used. It also indicates if creation is blocked or if a grace period is active. ```erb <% s = current_organization.limit(:projects) %>
<%= s.key.to_s.humanize %>: <%= s.current %> / <%= s.allowed %> (<%= s.percent_used.round(1) %>%)
<% if s.blocked %>
Creation blocked due to plan limits
<% elsif s.grace_active %>
Over limit — grace active until <%= s.grace_ends_at %>
<% end %> ```