Jumpstart docs logo Back to the app

Accounts

Accounts are a core piece of functionality for many applications these days and Jumpstart comes preconfigured with them so you don't have to do any of the heavy lifting.

Personal Account

Every user has a personal account they are an admin of. A personal account does not allow other users on it. This allows our code to work exactly the same whether we're adding resources privately for a user or a account of users.

GitHub is a great example of this case. Repositories can be personal or on an organization (their name for accounts) and by setting them up this way, we can have our code treat them exactly the same.

There is a configuration option that can be found at http://localhost:3000/jumpstart#accounts if you have the server running. In the first section labeled Accounts, there is a checkbox for enabling/disabling personal accounts. If checked, every new user that signs up for your application will be given a personal account by default. This happens via an after_create callback that comes from the UserAccounts concern which is included in the User.rb class:

# app/models/concerns/user_accounts.rb
after_create :create_default_account, unless: :skip_default_account?

After a new user record has been successfully created, this callback will be called and a personal account will be created for the new user unless you have disabled this feature in the Jumpstart configuration for your application via the checkbox mentioned previously at http://localhost:3000/jumpstart#accounts

With this in place, when an existing user creates a new account it will use the default setting of personal: false, which is setup in the migration for the accounts table:

t.boolean "personal", default: false

Additional Accounts

Users can create additional accounts and invite other users to join them. Once created, users can switch which account they're viewing from their account dropdown in the navbar.

Each account has separate billing, which allows you to setup flexible subscriptions based upon the account. This is also similar to GitHub where you can pay for a personal account or you can pay for an organization account.

If you don't want to use the accounts functionality, you can simply remove links to the accounts. We encourage you to keep the accounts functionality around as it allows you flexibility in the future should you choose to implement accounts later on.

Account Roles

Users can be assigned a role for each account they are a part of. By default, we only provide an admin role, but you can add more roles in app/models/account_user.rb. These roles will be listed in the UI when adding or editing a account member. You should not use a reserved word (like "user") as the name of a role; this will cause an error when attempting to create an account.

You can check the role on the account member to restrict access to certain functionality on the account as needed.

To access the current account member or roles, you can use the following helpers in your controllers and views:

current_account_user #=> AccountUser
current_roles #=> [:admin]

You can also access the roles individually on the AccountUser model:

account_user = AccountUser.new
account_user.admin? #=> false
account_user.admin = true
account_user.admin? #=> true
account_user.active_roles #=> [:admin]

Multitenancy

By popular request, we support "multitenancy" by selecting the current account and scoping all model queries to the set account. We're using the acts_as_tenant gem to power this feature.

Multitenancy is optional and must be opted in for each model that you want scoped to tenants. Any models without multitenancy will be globally available. We recommend you keep Users, Accounts, etc globally available outside tenants.

To scope a resource to a tenant, make sure your model has an account_id:integer column in the database.

Then you can add acts_as_tenant :account to the model.

class Project
    acts_as_tenant :account
  end

This will automatically add a belongs_to :account association and scope all queries on the model to the current account. Project.all will produce the same results as current_account.projects.

If current_account is nil, then all records will be returned. This can be changed to raise an exception if current account is nil by adding this initializer:

# config/initializers/acts_as_tenant.rb

ActsAsTenant.configure do |config|
  config.require_tenant = true
end

By enabling this feature, you will receive a ActsAsTenant::NoTenant when calling Project.all instead.

Account Switching

A user can switch which account they are viewing by clicking on the accounts in the navbar.

There are several different ways users can switch between accounts:

  • Session cookies (default)
  • Path /:account_id/
  • Subdomain
  • Custom Domain

Each of these options provides some flexibility for how accounts can be accessed:

Session cookies are the simplest and require no additional configuration.

Path switching prepends all routes with the current account ID. This is called the script_name and is filtered out in a Rails middleware automatically. To change accounts, you must provide the script name in the URL helpers: link_to "Home", root_url(script_name: "/#{account.id}"

Subdomain switching uses the first subdomain to determine the account. This requires wildcard DNS records to point *.example.com to your app and additional setup in your test suite to configure the host when making requests.

Custom Domain allows your users to provide their own domain to use your app. This requires customers to setup DNS records to point to your server. You'll also have to respond to these and make sure you generate SSL certificates for these domains. Since you cannot guarantee the user will setup their DNS records correctly, this option often is used in conjunction with subdomain switching to provide a fallback method of accessing the account.

Single log in across all sub domains

By default, users will be required to enter their credentials for each of their subdomains. If instead you want them to log a single time and have access to all their subdomains, add these two lines:

# config/application.rb
config.session_store :cookie_store, :key => '_some_key', :domain => '.lvh.me'
# config/environments/test.rb
config.session_store :cookie_store, :key => '_some_key', :domain => '.example.com'