From 1ea07d34d912830d561ea8c41313bfc7280bbe9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Pablo=20Fern=C3=A1ndez?= Date: Sun, 18 Sep 2011 11:05:29 +0300 Subject: [PATCH 1/4] Don't forget the previous tenant when going into a with_tenant block. --- lib/multitenant.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/multitenant.rb b/lib/multitenant.rb index 44684a2..b83b700 100644 --- a/lib/multitenant.rb +++ b/lib/multitenant.rb @@ -8,10 +8,11 @@ class << self # execute a block scoped to the current tenant # unsets the current tenant after execution def with_tenant(tenant, &block) + previous_tenant = Multitenant.current_tenant Multitenant.current_tenant = tenant yield ensure - Multitenant.current_tenant = nil + Multitenant.current_tenant = previous_tenant end end From 23c0961fff7e7b3ab6e00feb39b985405a48d821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Pablo=20Fern=C3=A1ndez?= Date: Tue, 20 Sep 2011 06:45:04 +0200 Subject: [PATCH 2/4] Test resetting the current_tenant to the previous one. --- spec/multitenant_spec.rb | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/spec/multitenant_spec.rb b/spec/multitenant_spec.rb index 6e2b783..c3bed9e 100644 --- a/spec/multitenant_spec.rb +++ b/spec/multitenant_spec.rb @@ -58,7 +58,25 @@ class Item < ActiveRecord::Base end it 'yields the block' do @executed.should == true - end + end + end + + describe 'Multitenant.with_tenant block with a previous tenant' do + before do + @previous = :whatever + Multitenant.current_tenant = @previous + @executed = false + Multitenant.with_tenant :foo do + Multitenant.current_tenant.should == :foo + @executed = true + end + end + it 'resets current_tenant after block runs' do + Multitenant.current_tenant.should == @previous + end + it 'yields the block' do + @executed.should == true + end end describe 'Multitenant.with_tenant block that raises error' do From 411626389cf032f92f6d3e61dc10abe7239e193c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Pablo=20Ferna=CC=81ndez?= Date: Wed, 7 Nov 2012 11:24:20 +0000 Subject: [PATCH 3/4] When setting a tenant as the current one, call a method in the tenant (a callback). This is useful when there's some extra settings to be done, like setting the global locale to match that of the tenant. --- lib/multitenant.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/multitenant.rb b/lib/multitenant.rb index b83b700..98ef9d4 100644 --- a/lib/multitenant.rb +++ b/lib/multitenant.rb @@ -7,9 +7,14 @@ class << self # execute a block scoped to the current tenant # unsets the current tenant after execution - def with_tenant(tenant, &block) + # @param [Object] tenant the new current tenant + # @param [Hash] options + # @option options [Symbol] :became_current_tenant_method (:became_current_tenant) name of the method to call on tenant after it became the current one (and before the block is run) + def with_tenant(tenant, options={}, &block) + options[:became_current_tenant_method] ||= :became_current_tenant previous_tenant = Multitenant.current_tenant Multitenant.current_tenant = tenant + tenant.send(options[:became_current_tenant_method]) if tenant.respond_to?(options[:became_current_tenant_method]) yield ensure Multitenant.current_tenant = previous_tenant From 24c77e9c89f133ae0139c5453b82723e484d0dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Pablo=20Ferna=CC=81ndez?= Date: Wed, 7 Nov 2012 11:49:11 +0000 Subject: [PATCH 4/4] Make sure the callback is run on current_tenant= as well. And tests. This unfortunately forces the name of the callback to be fixed. If necessary, it can be a global configuration, but at this point it seems to add more trouble than it's worth. --- lib/multitenant.rb | 14 ++++++++------ spec/multitenant_spec.rb | 18 +++++++++++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/multitenant.rb b/lib/multitenant.rb index 98ef9d4..5ba501a 100644 --- a/lib/multitenant.rb +++ b/lib/multitenant.rb @@ -3,18 +3,20 @@ # Multitenant: making cross tenant data leaks a thing of the past...since 2011 module Multitenant class << self - attr_accessor :current_tenant + attr_reader :current_tenant + + def current_tenant=(tenant) + @current_tenant = tenant + @current_tenant.became_current_tenant if @current_tenant.respond_to?(:became_current_tenant) + @current_tenant + end # execute a block scoped to the current tenant # unsets the current tenant after execution # @param [Object] tenant the new current tenant - # @param [Hash] options - # @option options [Symbol] :became_current_tenant_method (:became_current_tenant) name of the method to call on tenant after it became the current one (and before the block is run) - def with_tenant(tenant, options={}, &block) - options[:became_current_tenant_method] ||= :became_current_tenant + def with_tenant(tenant, &block) previous_tenant = Multitenant.current_tenant Multitenant.current_tenant = tenant - tenant.send(options[:became_current_tenant_method]) if tenant.respond_to?(options[:became_current_tenant_method]) yield ensure Multitenant.current_tenant = previous_tenant diff --git a/spec/multitenant_spec.rb b/spec/multitenant_spec.rb index c3bed9e..3d259ba 100644 --- a/spec/multitenant_spec.rb +++ b/spec/multitenant_spec.rb @@ -23,6 +23,11 @@ class Company < ActiveRecord::Base has_many :users + attr_accessor :now_is_current_tenant + + def became_current_tenant + self.now_is_current_tenant = true + end end class User < ActiveRecord::Base belongs_to :company @@ -41,8 +46,13 @@ class Item < ActiveRecord::Base after { Multitenant.current_tenant = nil } describe 'Multitenant.current_tenant' do - before { Multitenant.current_tenant = :foo } - it { Multitenant.current_tenant == :foo } + before do + @company = Company.create!(:name => 'foo') + @company.now_is_current_tenant.should == nil + Multitenant.current_tenant = @company + end + it { Multitenant.current_tenant.should == @company } + it { @company.now_is_current_tenant.should == true } end describe 'Multitenant.with_tenant block' do @@ -94,12 +104,13 @@ class Item < ActiveRecord::Base end it 'yields the block' do @executed.should == true - end + end end describe 'User.all when current_tenant is set' do before do @company = Company.create!(:name => 'foo') + @company.now_is_current_tenant.should == nil @company2 = Company.create!(:name => 'bar') @user = @company.users.create! :name => 'bob' @@ -110,6 +121,7 @@ class Item < ActiveRecord::Base end it { @users.length.should == 1 } it { @users.should == [@user] } + it { @company.now_is_current_tenant.should == true } end describe 'Item.all when current_tenant is set' do