rails_multitenant 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20d2743f52770c7de4e81ae6936148c6c1f474f2
4
- data.tar.gz: a533e376642c62f6beb78570ef94eaa99d57f6d8
3
+ metadata.gz: 7fa50760b463e1f9b31abc6a19d13e863dc5604a
4
+ data.tar.gz: 7af84280e893555c5c40a4e55cfad57bba8d4252
5
5
  SHA512:
6
- metadata.gz: 213daa229aaf72402c6964eeddb045b5f33f2da1dbd2eecf01eeb568f04f97336ddad5af5c3fee90de13531b4090511432438796746dd2694d4af454f081e5f5
7
- data.tar.gz: 00ab17d047dc6117014bbb86b93ad7fcc731a067347c6d8437fc575350b8ea314096ba89a76dfbc6a8e0ca413be2db2108492c85e8771d00016072d3919cd0b8
6
+ metadata.gz: b7aca78e340f93da77d625dae54d1c372053fe732032ec7f4acf2b651a436d75fa502895ef212df9a37318a080bf683fa0d4ed785301138bc79ff70d20d06be3
7
+ data.tar.gz: 91f20b900cd76a6e8afae4ebd8d239b456c74ea1cc0170d660e05109156ac2b28c459fd330c54d56169de7efda6ee935489f1b64fc8697d3e69ed86c33181558
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ### 0.2.0 (unreleased)
4
+ * Merged [PR 2](https://github.com/salsify/rails-multitenant/pull/2) which adds support for
5
+ multi-tenancy based on a foreign key to an external model. As part of this the `multitenant_model_on`
6
+ method was renamed to `multitenant_on_model`.
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec) do |task|
5
+ task.verbose = false
6
+ end
7
+
8
+ task default: :spec
@@ -39,7 +39,7 @@ module RailsMultitenant
39
39
 
40
40
  def current_registry_obj
41
41
  key_class = respond_to?(:base_class) ? base_class : self
42
- "#{key_class.name.downcase}_obj".to_sym
42
+ "#{key_class.name.underscore}_obj".to_sym
43
43
  end
44
44
  end
45
45
 
@@ -103,12 +103,12 @@ module RailsMultitenant
103
103
 
104
104
  def current_instance_registry_id
105
105
  key_class = respond_to?(:base_class) ? base_class : self
106
- "#{key_class.name.downcase}_id".to_sym
106
+ "#{key_class.name.underscore}_id".to_sym
107
107
  end
108
108
 
109
109
  def current_instance_registry_obj
110
110
  key_class = respond_to?(:base_class) ? base_class : self
111
- "#{key_class.name.downcase}_obj".to_sym
111
+ "#{key_class.name.underscore}_obj".to_sym
112
112
  end
113
113
 
114
114
  include RegistryDependentOn
@@ -132,6 +132,7 @@ module RailsMultitenant
132
132
  def set(symbol, value)
133
133
  globals[symbol] = value
134
134
  end
135
+ alias_method :[]=, :set
135
136
 
136
137
  # delete this global
137
138
  def delete(symbol)
@@ -152,6 +153,7 @@ module RailsMultitenant
152
153
  def get(symbol)
153
154
  globals[symbol]
154
155
  end
156
+ alias_method :[], :get
155
157
 
156
158
  # Duplicate the registry
157
159
  def duplicate_registry
@@ -160,10 +162,10 @@ module RailsMultitenant
160
162
  end
161
163
  end
162
164
 
163
- # Run a block of code with an empty registry
164
- def with_isolated_registry
165
+ # Run a block of code with an the given registry
166
+ def with_isolated_registry(registry = {})
165
167
  prior_globals = globals
166
- self.globals = {}
168
+ self.globals = registry
167
169
  yield
168
170
  ensure
169
171
  self.globals = prior_globals
@@ -1,14 +1,6 @@
1
1
  module RailsMultitenant
2
2
  module MultitenantModel
3
3
  extend ActiveSupport::Concern
4
- =begin
5
- included do
6
- belongs_to :organization
7
- validates_presence_of :organization_id
8
- scope :from_current_org, -> { where(organization_id: Organization.current_id) }
9
- default_scope { from_current_org }
10
- end
11
- =end
12
4
 
13
5
  included do
14
6
  class << self
@@ -18,19 +10,29 @@ module RailsMultitenant
18
10
 
19
11
  module ClassMethods
20
12
 
21
- def multitenant_model_on(context_entity)
22
- @context_entity_id_field = "#{context_entity}_id"
13
+ def multitenant_on(context_entity_id_field)
14
+ self.context_entity_id_field = context_entity_id_field
15
+ validates_presence_of context_entity_id_field
16
+
17
+ context_entity = context_entity_id_field.to_s.gsub(/_id$/, '')
23
18
  scope_sym = "from_current_#{context_entity}".to_sym
24
19
 
25
- belongs_to context_entity
26
- validates_presence_of context_entity_id_field
27
- scope scope_sym, -> { where(context_entity_id_field => context_entity.to_s.classify.constantize.current_id) }
20
+ scope scope_sym, -> do
21
+ where(context_entity_id_field => GlobalContextRegistry[context_entity_id_field])
22
+ end
23
+
28
24
  default_scope { send(scope_sym) }
25
+
29
26
  define_method "strip_#{context_entity}_scope" do
30
27
  unscope(where: context_entity_id_field)
31
28
  end
32
29
  end
33
30
 
31
+ def multitenant_on_model(context_entity)
32
+ multitenant_on("#{context_entity}_id".to_sym)
33
+ belongs_to context_entity
34
+ end
35
+
34
36
  def validates_multitenant_uniqueness_of(*attr_names)
35
37
  options = attr_names.extract_options!.symbolize_keys
36
38
  existing_scope = Array.wrap(options.delete(:scope))
@@ -0,0 +1,5 @@
1
+ RSpec::Matchers.define(:be_multitenant_on) do |expected|
2
+ match do |actual|
3
+ actual.context_entity_id_field == expected
4
+ end
5
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsMultitenant
2
- VERSION = "0.1.0"
2
+ VERSION = '0.2.0'
3
3
  end
@@ -3,3 +3,5 @@ require 'active_record'
3
3
 
4
4
  require "rails_multitenant/global_context_registry"
5
5
  require "rails_multitenant/multitenant_model"
6
+
7
+ # rails_multitenant/rspec has to be explicitly included by clients who want to use it
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'rails_multitenant/rspec'
3
+
4
+ describe "be_multitenant_on matcher" do
5
+ it "accepts a valid context field id" do
6
+ expect(ExternalItem).to be_multitenant_on(:external_organization_id)
7
+ end
8
+
9
+ it "rejects an invalid context field id" do
10
+ expect(ExternalItem).not_to be_multitenant_on(:other_field)
11
+ end
12
+ end
data/spec/db/schema.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  # encoding: UTF-8
2
2
 
3
- ActiveRecord::Schema.define(:version => 0) do
3
+ ActiveRecord::Schema.define(version: 0) do
4
4
 
5
- create_table(:organizations, force: true) do |t|
6
- t.string :name
7
- end
5
+ create_table(:organizations, force: true)
8
6
 
9
7
  create_table(:items, force: true) do |t|
10
- t.string :name
11
8
  t.integer :organization_id
12
9
  end
13
10
 
11
+ create_table(:external_items, force: true) do |t|
12
+ t.integer :external_organization_id
13
+ end
14
14
  end
15
15
 
16
16
  class Organization < ActiveRecord::Base
@@ -19,5 +19,11 @@ end
19
19
 
20
20
  class Item < ActiveRecord::Base
21
21
  include RailsMultitenant::MultitenantModel
22
- multitenant_model_on :organization
22
+ multitenant_on_model :organization
23
+ end
24
+
25
+ class ExternalItem < ActiveRecord::Base
26
+ include RailsMultitenant::MultitenantModel
27
+ multitenant_on :external_organization_id
23
28
  end
29
+
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ include RailsMultitenant
3
+
4
+ describe ExternalItem do
5
+
6
+ let!(:external_item1) { as_external_org(1) { ExternalItem.create! } }
7
+
8
+ let!(:external_item2) { as_external_org(2) { ExternalItem.create! } }
9
+ let!(:external_item3) { as_external_org(2) { ExternalItem.create! } }
10
+
11
+ specify 'org1 has the correct external items' do
12
+ as_external_org(1) do
13
+ expect(ExternalItem.all).to eq [external_item1]
14
+ end
15
+ end
16
+
17
+ specify 'org2 has the correct external items' do
18
+ as_external_org(2) do
19
+ expect(ExternalItem.all).to match_array [external_item2, external_item3]
20
+ end
21
+ end
22
+
23
+ it 'does not return external items from other orgs' do
24
+ as_external_org(2) do
25
+ expect(ExternalItem.where(id: external_item1.id)).to eq []
26
+ end
27
+ end
28
+
29
+ def as_external_org(id, &block)
30
+ GlobalContextRegistry.with_isolated_registry(external_organization_id: id, &block)
31
+ end
32
+
33
+ end
@@ -15,6 +15,16 @@ describe GlobalContextRegistry do
15
15
  end
16
16
  end
17
17
 
18
+ describe '.[] and .[]=' do
19
+ before do
20
+ GlobalContextRegistry[:boo] = 'baz'
21
+ end
22
+
23
+ specify do
24
+ expect(GlobalContextRegistry[:boo]).to eq 'baz'
25
+ end
26
+ end
27
+
18
28
  describe '.delete' do
19
29
  specify do
20
30
  expect(GlobalContextRegistry.delete(:foo)).to eq 'bar'
@@ -28,6 +38,12 @@ describe GlobalContextRegistry do
28
38
  expect(GlobalContextRegistry.get(:foo)).to be_nil
29
39
  end
30
40
  end
41
+
42
+ specify do
43
+ GlobalContextRegistry.with_isolated_registry(foo: 'updated') do
44
+ expect(GlobalContextRegistry.get(:foo)).to eq 'updated'
45
+ end
46
+ end
31
47
  end
32
48
 
33
49
  describe '.replace_registry and .new_registry' do
data/spec/item_spec.rb CHANGED
@@ -6,11 +6,11 @@ require 'spec_helper'
6
6
 
7
7
  describe Item do
8
8
 
9
- let!(:item1) { Item.create(name: 'item1') }
9
+ let!(:item1) { Item.create! }
10
10
 
11
- let!(:org2) { Organization.create(name: 'org2') }
12
- let!(:item2) { org2.as_current { Item.create(name: 'item2') } }
13
- let!(:item3) { org2.as_current { Item.create(name: 'item3') } }
11
+ let!(:org2) { Organization.create! }
12
+ let!(:item2) { org2.as_current { Item.create! } }
13
+ let!(:item3) { org2.as_current { Item.create! } }
14
14
 
15
15
  specify 'default org should have one item' do
16
16
  expect(Item.all).to eq [ item1 ]
data/spec/spec_helper.rb CHANGED
@@ -30,8 +30,6 @@ require 'db/schema'
30
30
  RSpec.configure do |config|
31
31
  config.order = 'random'
32
32
 
33
- config.add_setting :test_org_id
34
-
35
33
  config.before(:suite) do
36
34
  DatabaseCleaner.clean_with(:truncation)
37
35
  end
@@ -40,9 +38,7 @@ RSpec.configure do |config|
40
38
  DatabaseCleaner.strategy = :transaction
41
39
  DatabaseCleaner.start
42
40
  RailsMultitenant::GlobalContextRegistry.new_registry
43
- org = Organization.create(name: 'test org')
44
- RSpec.configuration.test_org_id = org.id
45
- Organization.current_id = RSpec.configuration.test_org_id
41
+ Organization.current_id = Organization.create!.id
46
42
  end
47
43
 
48
44
  config.after(:each) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_multitenant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Breault
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-23 00:00:00.000000000 Z
11
+ date: 2016-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -158,6 +158,7 @@ files:
158
158
  - ".gitignore"
159
159
  - ".ruby-version"
160
160
  - ".travis.yml"
161
+ - CHANGELOG.md
161
162
  - CODE_OF_CONDUCT.md
162
163
  - Gemfile
163
164
  - README.md
@@ -167,11 +168,13 @@ files:
167
168
  - lib/rails_multitenant.rb
168
169
  - lib/rails_multitenant/global_context_registry.rb
169
170
  - lib/rails_multitenant/multitenant_model.rb
171
+ - lib/rails_multitenant/rspec.rb
170
172
  - lib/rails_multitenant/version.rb
171
- - log/test.log
172
173
  - rails_multitenant.gemspec
174
+ - spec/be_multitenant_on_matcher_spec.rb
173
175
  - spec/db/database.yml
174
176
  - spec/db/schema.rb
177
+ - spec/external_item_spec.rb
175
178
  - spec/global_context_registry_spec.rb
176
179
  - spec/item_spec.rb
177
180
  - spec/spec_helper.rb
@@ -200,8 +203,10 @@ signing_key:
200
203
  specification_version: 4
201
204
  summary: Automatically configures multiple tenants in a Rails environment
202
205
  test_files:
206
+ - spec/be_multitenant_on_matcher_spec.rb
203
207
  - spec/db/database.yml
204
208
  - spec/db/schema.rb
209
+ - spec/external_item_spec.rb
205
210
  - spec/global_context_registry_spec.rb
206
211
  - spec/item_spec.rb
207
212
  - spec/spec_helper.rb