Moneygun - Simple Rails 8 SaaS Boilerplate
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.

π Features
Core Functionality
- Multi-tenant Architecture: Route-based organization management
- Authentication & Authorization: Built with Devise and Pundit
- Subscription Management: Integrated Stripe payments via Pay gem
- Team Management: Organization creation, member invitations, and role management
- Modern UI: Clean, responsive design that you can easily extend
- Dark mode & Themes
π‘ Teams as MVP: Teams should be an MVP feature! - Learn why implementing teams early is crucial for SaaS applications.
Deployment
Deploy to fly.io
Useful commands:
fly deploy
fly secrets set RAILS_MASTER_KEY=$(cat config/credentials/production.key) --app moneygun
fly ssh console --app moneygun
bin/rails console
Developer Experience
- Complete Test Coverage
- Nested Resource Generation: Fast development with nested scaffold generators
π― Why Moneygun?
Route-Based Multi-tenancy
Unlike traditional approaches (subdomains, user.organization_id), Moneygun uses route-based multi-tenancy which offers several advantages:
- Support for multiple organizations in different browser tabs
- No complex subdomain configuration required
π Video Tutorials
- 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
Resource Organization
Resources are organized in a logical hierarchy:
/organizations/:id/projects/:id/tasks/:id
This structure provides:
- Clear resource ownership
- Intuitive navigation
- Easy access control
- Simplified querying
π οΈ Getting Started
- Clone the repository:
git clone git@github.com:yshmarov/moneygun.git your_project_name
# git clone https://github.com/yshmarov/moneygun.git your_project_name
cd your_project_name
git remote rename origin moneygun
git remote add origin https://github.com/your-account/your-repo.git # Replace with your new Git repository url
git push -u origin main
- Set up the application:
bin/setup
- Start the development server:
bin/dev
π³ Stripe Integration
Moneygun uses the Pay gem for handling Stripe subscriptions. Here's how to set it up:
1. Configure Stripe Credentials
Add your Stripe credentials to your Rails credentials:
rails credentials:edit
# advanced usage
export EDITOR="/Applications/Cursor.app/Contents/MacOS/Cursor --wait"
rails credentials:edit --environment=development
rails credentials:edit --environment=test
rails credentials:edit --environment=production
Add the following structure:
stripe:
publishable_key: sk_
public_key: pk_
webhook_receive_test_events: true
signing_secret:
- whsec_
2. Create Stripe Products and Prices
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:
- Create a product named
Pro plan
- Add two prices:
- Monthly: $99/month
- Yearly: $999/year
- Create a product named
3. Configure Plans
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
4. Stripe webhooks
For development, Stripe webhook listener is already configured in Procfile.dev
stripe listen --forward-to localhost:3000/pay/webhooks/stripe
To enable webhooks:
- Development: Click here to create a new Stripe webhook with all the events pre-filled.
- Production: Click here to create a new Stripe webhook with all the events pre-filled.
Example production webhook url: https://moneygun.com/pay/webhooks/stripe
Require active subscription to access a resource
You can use the require_subscription before_action to protect routes:
before_action :require_subscription
private
def require_subscription
unless Current.organization.has_access?
flash[:alert] = "You need to subscribe to access this page."
redirect_to organization_subscriptions_url(Current.organization)
end
end
Subscription Status Indicators
Use the subscription status helper to show subscription state:
subscription_status_label(organization)
# Returns:
# π΄ - No subscription
# π - Subscription cancelled (on grace period)
# π’ - Active subscription
π·ββοΈ Development Guide
Resource Generation
Generate nested resources quickly using the nested_scaffold gem:
rails generate nested_scaffold organization/project name
Authorization
Generate Pundit policies for your resources:
rails g pundit:policy project
Best Practices
Resource Associations
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
Organization Scoping
Scope downstream models to organization for easier querying:
class Task < ApplicationRecord
belongs_to :organization
belongs_to :project
end
π§ͺ Testing
Run the test suite:
rails test:all
Code Quality
# ERB linting
bundle exec erb_lint --lint-all -a
# Ruby linting
bundle exec rubocop -A
# Alphabetically sort i18n keys
i18n-tasks normalize
oAuth
Callback url examples:
https://moneygun.fly.dev/auth/google_oauth2/callback
http://localhost:3000/auth/google_oauth2/callback
β¨ Contributors
π License
This project is licensed under the MIT License - see the LICENSE file for details.
π Acknowledgments
- Design inspiration from Basecamp, Linear, Trello, Discord, and Slack
- Bullet Train for SaaS patterns and inspiration (obfuscates_id, super scaffolding, teams architecture)
- Jumpstart Pro & co for maintaining the magnificent gems pay, acts_as_tenant



