ErwinM / acts_as_tenant

Easy multi-tenancy for Rails in a shared database setup.
MIT License
1.53k stars 262 forks source link

Add additional pkeys to scope if given #323

Open mylesboone opened 8 months ago

mylesboone commented 8 months ago

This allows for the user, when setting up acts_as_tenant for a model, to specify an option for a method that the tenant responds to that will give additional pkeys for including in the default scope of the data.

This allows for data from multiple tenants to be read in a tenant (without changing behavior of writing data). It works much in the same way that has_global_records does, but rather than global records, allows for other tenants' data to be included.

excid3 commented 8 months ago

Can you provide tests for this?

mylesboone commented 8 months ago

@excid3 I definitely can. I put in this PR to get an idea if something like this would be welcomed. If it is, I will add tests and also need to modify the validates_uniqueness_to_tenant, depending on what behavior is desired (I don't use that method, so I'm not sure if that method should validate uniqueness to all tenant pkeys provided, or just the one used for writing new data, the "main" one).

excid3 commented 8 months ago

I think we need a good use-case / example to show why this is useful and should be added. That will help on how best to handle other changes if it makes sense to include.

mylesboone commented 8 months ago

@excid3 I have a couple of use cases for two different projects. Both follow a very similar data-driven need though. In both cases, there's a master tenant that needs access to several child tenants' data, while the child tenant should only see its own data. Here's an example for a situation: In this case a Users::Salesperson has access to all their Sale's, and the Users::Manager has access to see their own Sale's along with all the Sale's of the Users::Salesperson's that they manage.

class User < ApplicationRecord
  has_many :sales
end

class Users::Manager < User
  has_many :employees, class_name: 'Users::Salesperson', foreign_key: :manager_id

  def employee_pkeys
    employees.ids
  end
end

class Users::Salesperson < User
  def employee_pkeys
    []
  end
end

class Sale < ApplicationRecord
  acts_as_tenant :user, additional_pkeys_method: :employee_pkeys
  belongs_to :user
end

> ActsAsTenant.current_tenant = Users::Manager.find(1)
> ActsAsTenant.current_tenant.employee_pkeys   #  [2, 3]
> Sale.all.to_sql   # SELECT sales.* FROM sales WHERE user_id IN (1,2,3)
> ActsAsTenant.current_tenant = Users::Salesperson.find(2)
> ActsAsTenant.current_tennat.employee_pkeys # []
> Sale.all.to_sql   # SELECT sales.* FROM sales WHERE user_id = 2
mylesboone commented 8 months ago

@excid3 thoughts? If you're on board, I'll write specs

mylesboone commented 6 days ago

@excid3 ^^ ?