0

I am using acts_as_tenant gem to manage a multi-tenant platform while using devise to manage users. A User in our system acts_as_tenant and belongs_to Organization. Organization acts_as_tenant and has_many Users.

We are having trouble understanding what the best way to ensure that upon sign up a User gets created, an Organization gets created, a Tenant gets created (based on the Org), and the current tenant gets saved subsequently setting the correct tenant_id on the User and Org model.

The problem is in order for a User to be valid it must have an organization and a tenant. So before validation happens we must create the org and the tenant, we are trying to do so with below code:

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :confirmable

  acts_as_tenant(:tenant)
  acts_as_paranoid
  belongs_to :organization

  before_validation :create_organization

  def create_organization
    if self.organization_id.nil?
      org = Organization.new(name: self.email)
      org.uuid = UUIDTools::UUID.random_create.to_s
      self.organization_id = org.uuid
    end
  end
end
class Organization < ApplicationRecord
  acts_as_tenant(:tenant)
  self.primary_key = :uuid
  has_many :users

  before_validation :create_tenant

  def create_tenant
    puts 'making new tenant'
    t = Tenant.new(:short_name => self.name)
  end
end
class ApplicationController < ActionController::Base
  set_current_tenant_through_filter
  before_action :find_current_tenant
  def find_current_tenant
    unless current_user.nil?
      set_current_tenant(current_user.organization.tenant)
    end
  end
end

But the users org and tenant are not being created before validation causing validation errors 'tenant must exist', 'org must exist'.

Any help on best practices here?

justin henricks
  • 467
  • 3
  • 6
  • 17

1 Answers1

0

I don't know your business logic but in order to do acts_as_tenant(:tenant) your model has to have a relation defined to tenant, which you don't seem to have. I think what you want to do (common use case) is:

class User < ActionController::Base
  belongs_to :organization
  acts_as_tenant(:organization)
end

class Organization < ActionController::Base
  self.primary_key = :uuid
  has_many :users
  # and nothing else
end

You don't set the current tenant on the model. That is not correct. You do that on the Application Controller, by doing set_current_tenant(current_user.organization) and nothing else

UPDATE: You mentionew a Tenant class now.

So now your organization class should define that relation

class Organization < ApplicationRecord
  acts_as_tenant(:tenant)
  self.primary_key = :uuid
  has_many :users
  belongs_to :tenant

  before_validation :create_tenant

  def create_tenant
    puts 'making new tenant'
    self.tenant ||= Tenant.create!(:short_name => self.name)
  end
end
Leticia Esperon
  • 2,499
  • 1
  • 18
  • 40
  • This is helping.. although our Organizations are tenanted too. Also, what is the correct way to associate my user to a new organization because I can't save the user or the organization until my tenant is set – justin henricks Aug 14 '19 at 17:57
  • What do you mean organizations are tenanted too? To what model? There is always one model that does not have the `acts_as_tenant` because it IS the tenant, in your case sounds like `organization` is that model – Leticia Esperon Aug 14 '19 at 18:10
  • Tenant is that model in our case – justin henricks Aug 14 '19 at 18:12
  • Okay so you are missing code on your post. Please include the `Tenant` model and the relation that the class `user` or `organization` has with that class. – Leticia Esperon Aug 14 '19 at 18:12
  • the User and Organization model are simply acts_as_tenant(:tenant) the tenant model is just: class Tenant < ActiveRecord::Base acts_as_paranoid include TenantHelper has_many :system_properties class << self def find!(tenant_id) find(tenant_id).as_current_tenant! end end end – justin henricks Aug 14 '19 at 18:15
  • But does `user` or `organization` `belong_to :tenant` ? Else it won't work! – Leticia Esperon Aug 14 '19 at 18:17
  • No, that's not true because the belongs_to gets set within the acts_as_tenant gem.. – justin henricks Aug 14 '19 at 18:26