moneygun

Rails Multitenancy boilerplate. Users-Memberships-Organizations. Row-based. Set tenant based on URL params by default

71
6
Ruby

Rails 8 Multitenancy Boilerplate

Core features

  • ✅ Registrations & Authentication (Devise + Devise invitable, but is quite easy to switch)
  • ✅ Create Organizations (aka Teams, Accounts, Workspaces, Tenants)
  • ✅ Invite Users to Organization & assign role (admin, member).
  • ✅ Organization admin can manage organization & members
  • ✅ Authorization
  • ✅ Complete test coverage
  • ✅ Basic UI design
  • ✅ Nested scaffold generators for fast development (/organizations/projects)

Moneygun features

About Row-level route-based multitenancy in Ruby on Rails

Teams should be an MVP feature!

Watch Screencast:

Why route-based multitenancy?

  • ✅ Easy to switch between organizations
  • ✅ Keep multiple organizations open in different tabs
  • ✅ No hassle configuring subdomains

Why deep nested routes?

Yes, this can generate an “long” url like /organizations/344/projects/4532/tasks/24342342/edit, but it preserves the logical hierarchy.

resources :organizations do
  resources :memberships
  resources :projects do
    resources :tasks do
    end
  end
end

I tried using OrganizationMiddlewhare like JumpstartPro does, but it felt too much of an unconventional approach.

Design inspiration

For example in Trello, you can have 2 unrelated boards open in 2 tabs.

Development

Getting started

  1. Clone the template repository:
git clone [email protected]:yshmarov/moneygun.git your_new_project_name
  1. Enter the project directory:
cd your_new_project_name
  1. Run the configuration and setup scripts:
bundle install
rails db:create db:migrate
  1. Start your application:
bin/dev

Resource assignments and references should be to Membership and not User!

🚫 Bad

# models/project.rb
  belongs_to :organization
  belongs_to :user

✅ Good

# models/project.rb
  belongs_to :organization
  belongs_to :membership

I recommend scoping downstream models to organization too. This way you can query them more easily.

# models/task.rb
  belongs_to :organization # <- THIS
  belongs_to :project

Generators

Inbox is an example of a well-integrated resource scoped to an organization. With pundit authorization and tests. Use it as an inspiration.

To quickly generate nested resources you can use gem nested_scaffold

rails generate nested_scaffold organization/project name

Generate a pundit policy:

rails g pundit:policy project

Testing & linting

I did not focus on system tests, because the frontend can evolve a lot.

There are quite a lot of tests covering authentication, authorization, and multitenancy.

# run all tests
rails test:all
bundle exec erb_lint --lint-all -a
bundle exec rubocop -A

Contributing

Feel free to raise an Issue or open a Pull Request!