SHIP YOUR NEXT APP FAST! Rails 8 SaaS Multitenancy boilerplate. Users-Memberships-Organizations. Row-based. Set tenant based on URL params.
A production-ready Ruby on Rails boilerplate for building multi-tenant SaaS applications. Built with best practices, modern tooling, and a focus on developer experience.
π‘ Teams as MVP: Teams should be an MVP feature! - Learn why implementing teams early is crucial for SaaS applications.
Unlike traditional approaches (subdomains, user.organization_id), Moneygun uses route-based multi-tenancy which offers several advantages:
Row-level Route-based Multitenancy
Learn how to implement row-level route-based multitenancy in Ruby on Rails
Multitenancy & Teams Boilerplate
Learn how to implement teams and multitenancy in your Rails application
Add ActsAsTenant to Existing Application
Step-by-step guide to adding ActsAsTenant to your existing Rails application
Build Your Next B2B SaaS
Enable Subscriptions with Stripe and launch your B2B SaaS application with Moneygun
Resources are organized in a logical hierarchy:
/organizations/:id/projects/:id/tasks/:id
This structure provides:
git clone [email protected]:yshmarov/moneygun.git your_project_name
cd your_project_name
bundle install
rails db:create db:migrate
bin/dev
Moneygun uses the Pay gem for handling Stripe subscriptions. Hereβs how to set it up:
Add your Stripe credentials to your Rails credentials:
rails credentials:edit
Add the following structure:
stripe:
private_key: sk_
public_key: pk_
webhook_receive_test_events: true
signing_secret:
- whsec_
You can create the required Stripe products and prices in two ways:
Automatically via seeds:
rails db:seed
This will create a βPro planβ product with monthly ($99) and yearly ($999) prices.
Manually in Stripe Dashboard:
Add your Stripe price IDs to config/settings.yml
:
shared:
plans:
- id: price_xxx # Monthly price ID
unit_amount: 9900
currency: USD
interval: month
- id: price_yyy # Yearly price ID
unit_amount: 99900
currency: USD
interval: year
For development, Stripe webhook listener is already configured in Procfile.dev
stripe listen --forward-to localhost:3000/pay/webhooks/stripe
To enable webhooks:
Example production webhook url: https://moneygun.com/pay/webhooks/stripe
Moneygun comes with built-in support for multiple themes. The application supports:
Themes can be applied by adding the appropriate class to the HTML element:
<html lang="en" class="h-full bg-gray-50 text-gray-900"></html>
<!-- Dark midnight theme -->
<html lang="en" class="h-full bg-gray-50 text-gray-900 midnight"></html>
<!-- Dark GitHub theme -->
<html lang="en" class="h-full bg-gray-50 text-gray-900 github"></html>
You can use the require_subscription
before_action to protect routes:
before_action :require_subscription
private
def require_subscription
unless current_organization.payment_processor.subscribed?
flash[:alert] = "You need to subscribe to access this page."
redirect_to organization_subscriptions_url(current_organization)
end
end
Use the subscription status helper to show subscription state:
subscription_status_label(organization)
# Returns:
# π΄ - No subscription
# π - Subscription cancelled (on grace period)
# π’ - Active subscription
Generate nested resources quickly using the nested_scaffold gem:
rails generate nested_scaffold organization/project name
Generate Pundit policies for your resources:
rails g pundit:policy project
Always associate resources with membership
instead of user
:
# β
Correct
class Project < ApplicationRecord
belongs_to :organization
belongs_to :membership
end
# β Avoid
class Project < ApplicationRecord
belongs_to :user
end
Scope downstream models to organization for easier querying:
class Task < ApplicationRecord
belongs_to :organization
belongs_to :project
end
Run the test suite:
rails test:all
# ERB linting
bundle exec erb_lint --lint-all -a
# Ruby linting
bundle exec rubocop -A
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.