mongoid-multitenancy 0.1.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjY1NTgwNWVlNWJhZWQ5NGI2MjVkZmZlMTY0ZWIyMjUyZDg3ZTdlNw==
5
+ data.tar.gz: !binary |-
6
+ YjFhODhkYjZiNTUwZDczYjA3NGZhMTViNDhkY2I3MWU1MTE1ODJhZA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ M2U5YjM5MWE0YWZjMWJiOTc0YzE3YmQ4ZDljNzgwYjc5YzE0YTRhMzczZmUy
10
+ YzBjMDJmYTNjY2FjMjBiNDljYTRlNDRiYTg1YTM0NjUzOGVmNjJmMjkyYzdh
11
+ N2NhMDcwMjI4MDc2MjJkOGJhMTEwNTg4ZGMzYTNkMjE2ZmQ4N2Q=
12
+ data.tar.gz: !binary |-
13
+ ODMwMDVjOTc4YTFiN2E2ZWQ5ODhlNmM1NTgyYWQ1MmEyMjI0ZTQwZmRlNjhj
14
+ NTMyY2U2YzE1N2U1MDNhM2I2MjdhMjhmOWRlZGJjM2U1ZWQyOGE0MTM4NmY3
15
+ NWY2MTdkMjY0M2EyZmY1YmFjZmYzMTk4MDA3MzlkNmEyM2FjYzQ=
data/Gemfile.lock CHANGED
@@ -1,52 +1,52 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mongoid-multitenancy (0.1)
4
+ mongoid-multitenancy (0.2.0)
5
5
  mongoid (~> 3)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (3.2.9)
11
- activesupport (= 3.2.9)
10
+ activemodel (3.2.13)
11
+ activesupport (= 3.2.13)
12
12
  builder (~> 3.0.0)
13
- activesupport (3.2.9)
14
- i18n (~> 0.6)
13
+ activesupport (3.2.13)
14
+ i18n (= 0.6.1)
15
15
  multi_json (~> 1.0)
16
16
  builder (3.0.4)
17
- database_cleaner (0.9.1)
18
- diff-lcs (1.1.3)
17
+ database_cleaner (1.0.1)
18
+ diff-lcs (1.2.4)
19
19
  i18n (0.6.1)
20
- mongoid (3.0.14)
21
- activemodel (~> 3.1)
22
- moped (~> 1.1)
20
+ mongoid (3.1.3)
21
+ activemodel (~> 3.2)
22
+ moped (~> 1.4.2)
23
23
  origin (~> 1.0)
24
24
  tzinfo (~> 0.3.22)
25
- mongoid-rspec (1.5.5)
25
+ mongoid-rspec (1.8.1)
26
26
  mongoid (>= 3.0.1)
27
27
  rake
28
28
  rspec (>= 2.9)
29
- moped (1.3.1)
30
- multi_json (1.5.0)
31
- origin (1.0.11)
32
- rake (10.0.3)
29
+ moped (1.4.5)
30
+ multi_json (1.7.3)
31
+ origin (1.1.0)
32
+ rake (10.0.4)
33
33
  redcarpet (2.2.2)
34
- rspec (2.12.0)
35
- rspec-core (~> 2.12.0)
36
- rspec-expectations (~> 2.12.0)
37
- rspec-mocks (~> 2.12.0)
38
- rspec-core (2.12.1)
39
- rspec-expectations (2.12.0)
40
- diff-lcs (~> 1.1.3)
41
- rspec-mocks (2.12.0)
42
- tzinfo (0.3.35)
43
- yard (0.8.3)
34
+ rspec (2.13.0)
35
+ rspec-core (~> 2.13.0)
36
+ rspec-expectations (~> 2.13.0)
37
+ rspec-mocks (~> 2.13.0)
38
+ rspec-core (2.13.1)
39
+ rspec-expectations (2.13.0)
40
+ diff-lcs (>= 1.1.3, < 2.0)
41
+ rspec-mocks (2.13.1)
42
+ tzinfo (0.3.37)
43
+ yard (0.8.6.1)
44
44
 
45
45
  PLATFORMS
46
46
  ruby
47
47
 
48
48
  DEPENDENCIES
49
- database_cleaner (~> 0.9)
49
+ database_cleaner (~> 1.0)
50
50
  mongoid-multitenancy!
51
51
  mongoid-rspec (~> 1.5)
52
52
  rake (~> 10.0)
data/README.md CHANGED
@@ -76,6 +76,11 @@ Scoping your models
76
76
  Adding `tenant` to your model declaration will scope that model to the current tenant **BUT ONLY if a current tenant has been set**.
77
77
  The association passed to the `tenant` function must be valid.
78
78
 
79
+ `tenant` accepts several options:
80
+
81
+ * :optional : set to true when the tenant can be optional
82
+ * :class_name, etc. : all the other options will be passed to the mongoid relation
83
+
79
84
  Some examples to illustrate this behavior:
80
85
 
81
86
  # This manually sets the current tenant for testing purposes. In your app this is handled by the gem.
@@ -92,6 +97,12 @@ Some examples to illustrate this behavior:
92
97
  article.client = another_client
93
98
  article.valid? # => false
94
99
 
100
+ **Optional tenant**
101
+
102
+ When setting an optional tenant, for example to allow shared instances between all the tenants, the default scope will return both the tenant and the free-tenant items. That means that using `Article.delete_all` or `Article.destroy_all` will remove the shared items too.
103
+
104
+ Article.all # => all articles where client_id.in [50ca04b86c82bfc125000025, nil]
105
+
95
106
  Rails
96
107
  -------------------
97
108
 
@@ -18,29 +18,44 @@ module Mongoid
18
18
 
19
19
  module ClassMethods
20
20
  # Access to the tenant field
21
- attr_reader :tenant_field
21
+ attr_reader :tenant_field, :tenant_options
22
22
 
23
- def tenant(association = :account)
23
+ def tenant(association = :account, options={})
24
+ @tenant_options = { optional: options.delete(:optional) }
24
25
  # Setup the association between the class and the tenant class
25
26
  # TODO: should index this association if no other indexes are defined => , index: true
26
- belongs_to association
27
+ belongs_to association, options
27
28
 
28
29
  # Get the tenant model and its foreign key
29
30
  fkey = reflect_on_association(association).foreign_key
30
31
  @tenant_field = fkey
31
32
 
32
33
  # Validates the presence of the association key
33
- validates_presence_of fkey
34
+ validates_presence_of fkey unless @tenant_options[:optional]
34
35
 
35
36
  # Set the current_tenant on newly created objects
36
- after_initialize lambda { |m| m.send "#{association}=".to_sym, Multitenancy.current_tenant if Multitenancy.current_tenant ; true }
37
+ after_initialize lambda { |m|
38
+ if Multitenancy.current_tenant #and !self.class.tenant_options[:optional]
39
+ m.send "#{association}=".to_sym, Multitenancy.current_tenant
40
+ end
41
+ true
42
+ }
37
43
 
38
44
  # Rewrite accessors to make tenant foreign_key/association immutable
39
45
  validate :check_tenant_immutability, :on => :update
40
46
 
41
47
  # Set the default_scope to scope to current tenant
42
48
  default_scope lambda {
43
- where(Multitenancy.current_tenant ? { self.tenant_field => Multitenancy.current_tenant.id } : nil)
49
+ criteria = if Multitenancy.current_tenant
50
+ if self.tenant_options[:optional]
51
+ #any_of({ self.tenant_field => Multitenancy.current_tenant.id }, { self.tenant_field => nil })
52
+ where({ self.tenant_field.to_sym.in => [Multitenancy.current_tenant.id, nil] })
53
+ else
54
+ where({ self.tenant_field => Multitenancy.current_tenant.id })
55
+ end
56
+ else
57
+ where(nil)
58
+ end
44
59
  }
45
60
  end
46
61
 
@@ -60,7 +75,7 @@ module Mongoid
60
75
 
61
76
  # Redefine 'delete_all' to take in account the default scope
62
77
  def delete_all(conditions = nil)
63
- self.where(conditions).delete
78
+ scoped.where(conditions).delete
64
79
  end
65
80
  end
66
81
  end
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Multitenancy
3
- VERSION = "0.1.1"
3
+ VERSION = "0.2"
4
4
  end
5
5
  end
@@ -21,6 +21,6 @@ Gem::Specification.new do |gem|
21
21
  gem.add_development_dependency('rspec', '~> 2.12')
22
22
  gem.add_development_dependency('yard', '~> 0.8')
23
23
  gem.add_development_dependency('mongoid-rspec', '~> 1.5')
24
- gem.add_development_dependency('database_cleaner', '~> 0.9')
24
+ gem.add_development_dependency('database_cleaner', '~> 1.0')
25
25
  gem.add_development_dependency('redcarpet', '~> 2.2')
26
26
  end
@@ -1,4 +1,4 @@
1
- class Client
1
+ class Account
2
2
  include Mongoid::Document
3
3
 
4
4
  field :name, :type => String
@@ -2,7 +2,7 @@ class Article
2
2
  include Mongoid::Document
3
3
  include Mongoid::Multitenancy::Document
4
4
 
5
- tenant(:client)
5
+ tenant(:client, :class_name => 'Account')
6
6
 
7
7
  field :slug, :type => String
8
8
  field :title, :type => String
@@ -0,0 +1,15 @@
1
+ class Page
2
+ include Mongoid::Document
3
+ include Mongoid::Multitenancy::Document
4
+
5
+ tenant(:client, :class_name => 'Account', :optional => true)
6
+
7
+ field :slug, :type => String
8
+ field :title, :type => String
9
+
10
+ validates_uniqueness_of :slug
11
+ validates_presence_of :slug
12
+ validates_presence_of :title
13
+
14
+ index({ :title => 1 })
15
+ end
@@ -1,8 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Mongoid::Multitenancy do
4
- let(:client) { Client.create!(:name => "client") }
5
- let(:another_client) { Client.create!(:name => "another client") }
4
+ let(:client) { Account.create!(:name => "client") }
5
+ let(:another_client) { Account.create!(:name => "another client") }
6
6
 
7
7
  before { Mongoid::Multitenancy.current_tenant = client }
8
8
  after { Mongoid::Multitenancy.current_tenant = nil }
@@ -21,28 +21,97 @@ describe Mongoid::Multitenancy do
21
21
  end
22
22
  end
23
23
 
24
- describe Article do
24
+ shared_examples_for "a tenantable model" do
25
+
25
26
  it { should belong_to(:client) }
26
- it { should validate_presence_of(:client_id) }
27
27
  it { should validate_uniqueness_of(:slug).scoped_to(:client_id) }
28
28
  it { should have_index_for(:client_id => 1, :title => 1) }
29
29
 
30
- let(:client) { Client.create!(:name => "client") }
31
- let(:another_client) { Client.create!(:name => "another client") }
30
+ let(:client) { Account.create!(:name => "client") }
31
+ let(:another_client) { Account.create!(:name => "another client") }
32
32
 
33
33
  describe ".initialize" do
34
34
  before { Mongoid::Multitenancy.current_tenant = client }
35
35
  after { Mongoid::Multitenancy.current_tenant = nil }
36
36
 
37
37
  it "should set the client field" do
38
- Article.new.client.should eq client
38
+ described_class.new.client.should eq client
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ describe Page do
45
+
46
+ it_behaves_like "a tenantable model"
47
+
48
+ it { should_not validate_presence_of(:client_id) }
49
+
50
+ let(:client) { Account.create!(:name => "client") }
51
+ let(:another_client) { Account.create!(:name => "another client") }
52
+
53
+ describe ".default_scope" do
54
+ before {
55
+ @itemC = described_class.create!(:title => "title C", :slug => "article-c")
56
+ Mongoid::Multitenancy.with_tenant(client) { @itemX = described_class.create!(:title => "title X", :slug => "article-x") }
57
+ Mongoid::Multitenancy.with_tenant(another_client) { @itemY = described_class.create!(:title => "title Y", :slug => "article-y") }
58
+ }
59
+
60
+ context "with a current tenant" do
61
+ before { Mongoid::Multitenancy.current_tenant = another_client }
62
+ after { Mongoid::Multitenancy.current_tenant = nil }
63
+
64
+ it "should filter on the current tenant / free-tenant items" do
65
+ described_class.all.to_a.should =~ [@itemY, @itemC]
66
+ end
67
+ end
68
+
69
+ context "without a current tenant" do
70
+ before { Mongoid::Multitenancy.current_tenant = nil }
71
+
72
+ it "should not filter on any tenant" do
73
+ described_class.all.to_a.should =~ [@itemC, @itemX, @itemY]
74
+ end
39
75
  end
40
76
  end
41
77
 
78
+ describe "#delete_all" do
79
+ before {
80
+ @itemC = described_class.create!(:title => "title C", :slug => "article-c")
81
+ Mongoid::Multitenancy.with_tenant(client) { @itemX = described_class.create!(:title => "title X", :slug => "article-x") }
82
+ Mongoid::Multitenancy.with_tenant(another_client) { @itemY = described_class.create!(:title => "title Y", :slug => "article-y") }
83
+ }
84
+
85
+ context "with a current tenant" do
86
+ it "should only delete the current tenant / free-tenant items" do
87
+ Mongoid::Multitenancy.with_tenant(another_client) { described_class.delete_all }
88
+ described_class.all.to_a.should =~ [@itemX]
89
+ end
90
+ end
91
+
92
+ context "without a current tenant" do
93
+ it "should delete all the pages" do
94
+ described_class.delete_all
95
+ described_class.all.to_a.should be_empty
96
+ end
97
+ end
98
+ end
99
+
100
+ end
101
+
102
+ describe Article do
103
+
104
+ it_behaves_like "a tenantable model"
105
+
106
+ it { should validate_presence_of(:client_id) }
107
+
108
+ let(:client) { Account.create!(:name => "client") }
109
+ let(:another_client) { Account.create!(:name => "another client") }
110
+
42
111
  describe ".default_scope" do
43
112
  before {
44
- Mongoid::Multitenancy.with_tenant(client) { @articleX = Article.create!(:title => "title X", :slug => "article-x") }
45
- Mongoid::Multitenancy.with_tenant(another_client) { @articleY = Article.create!(:title => "title Y", :slug => "article-y") }
113
+ Mongoid::Multitenancy.with_tenant(client) { @itemX = described_class.create!(:title => "title X", :slug => "article-x") }
114
+ Mongoid::Multitenancy.with_tenant(another_client) { @itemY = described_class.create!(:title => "title Y", :slug => "article-y") }
46
115
  }
47
116
 
48
117
  context "with a current tenant" do
@@ -50,7 +119,7 @@ describe Article do
50
119
  after { Mongoid::Multitenancy.current_tenant = nil }
51
120
 
52
121
  it "should filter on the current tenant" do
53
- Article.all.to_a.should == [@articleY]
122
+ described_class.all.to_a.should =~ [@itemY]
54
123
  end
55
124
  end
56
125
 
@@ -58,7 +127,7 @@ describe Article do
58
127
  before { Mongoid::Multitenancy.current_tenant = nil }
59
128
 
60
129
  it "should not filter on any tenant" do
61
- Article.all.to_a.should == [@articleX, @articleY]
130
+ described_class.all.to_a.should =~ [@itemX, @itemY]
62
131
  end
63
132
  end
64
133
  end
@@ -88,22 +157,23 @@ describe Article do
88
157
 
89
158
  describe "#delete_all" do
90
159
  before {
91
- Mongoid::Multitenancy.with_tenant(client) { @articleX = Article.create!(:title => "title X", :slug => "article-x") }
92
- Mongoid::Multitenancy.with_tenant(another_client) { @articleY = Article.create!(:title => "title Y", :slug => "article-y") }
160
+ Mongoid::Multitenancy.with_tenant(client) { @itemX = described_class.create!(:title => "title X", :slug => "article-x") }
161
+ Mongoid::Multitenancy.with_tenant(another_client) { @itemY = described_class.create!(:title => "title Y", :slug => "article-y") }
93
162
  }
94
163
 
95
164
  context "with a current tenant" do
96
165
  it "should only delete the current tenant articles" do
97
- Mongoid::Multitenancy.with_tenant(another_client) { Article.delete_all }
98
- Article.all.to_a == [@articleX]
166
+ Mongoid::Multitenancy.with_tenant(another_client) { described_class.delete_all }
167
+ described_class.all.to_a.should =~ [@itemX]
99
168
  end
100
169
  end
101
170
 
102
171
  context "without a current tenant" do
103
172
  it "should delete all the articles" do
104
- Article.delete_all
105
- Article.all.to_a.should be_empty
173
+ described_class.delete_all
174
+ described_class.all.to_a.should be_empty
106
175
  end
107
176
  end
108
177
  end
178
+
109
179
  end
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-multitenancy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
5
- prerelease:
4
+ version: '0.2'
6
5
  platform: ruby
7
6
  authors:
8
7
  - Aymeric Brisse
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-12-14 00:00:00.000000000 Z
11
+ date: 2013-05-16 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: mongoid
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
@@ -46,7 +41,6 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: rspec
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ~>
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ~>
60
53
  - !ruby/object:Gem::Version
@@ -62,7 +55,6 @@ dependencies:
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: yard
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ~>
68
60
  - !ruby/object:Gem::Version
@@ -70,7 +62,6 @@ dependencies:
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ~>
76
67
  - !ruby/object:Gem::Version
@@ -78,7 +69,6 @@ dependencies:
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: mongoid-rspec
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - ~>
84
74
  - !ruby/object:Gem::Version
@@ -86,7 +76,6 @@ dependencies:
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - ~>
92
81
  - !ruby/object:Gem::Version
@@ -94,23 +83,20 @@ dependencies:
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: database_cleaner
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - ~>
100
88
  - !ruby/object:Gem::Version
101
- version: '0.9'
89
+ version: '1.0'
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - ~>
108
95
  - !ruby/object:Gem::Version
109
- version: '0.9'
96
+ version: '1.0'
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: redcarpet
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
101
  - - ~>
116
102
  - !ruby/object:Gem::Version
@@ -118,7 +104,6 @@ dependencies:
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
108
  - - ~>
124
109
  - !ruby/object:Gem::Version
@@ -142,37 +127,38 @@ files:
142
127
  - lib/mongoid/multitenancy/document.rb
143
128
  - lib/mongoid/multitenancy/version.rb
144
129
  - mongoid-multitenancy.gemspec
130
+ - spec/models/account.rb
145
131
  - spec/models/article.rb
146
- - spec/models/client.rb
132
+ - spec/models/page.rb
147
133
  - spec/mongoid-multitenancy_spec.rb
148
134
  - spec/spec_helper.rb
149
135
  homepage: https://github.com/PerfectMemory/mongoid-multitenancy
150
136
  licenses: []
137
+ metadata: {}
151
138
  post_install_message:
152
139
  rdoc_options: []
153
140
  require_paths:
154
141
  - lib
155
142
  required_ruby_version: !ruby/object:Gem::Requirement
156
- none: false
157
143
  requirements:
158
144
  - - ! '>='
159
145
  - !ruby/object:Gem::Version
160
146
  version: '0'
161
147
  required_rubygems_version: !ruby/object:Gem::Requirement
162
- none: false
163
148
  requirements:
164
149
  - - ! '>='
165
150
  - !ruby/object:Gem::Version
166
151
  version: '0'
167
152
  requirements: []
168
153
  rubyforge_project:
169
- rubygems_version: 1.8.24
154
+ rubygems_version: 2.0.1
170
155
  signing_key:
171
- specification_version: 3
156
+ specification_version: 4
172
157
  summary: Support of a multi-tenant database with Mongoid
173
158
  test_files:
159
+ - spec/models/account.rb
174
160
  - spec/models/article.rb
175
- - spec/models/client.rb
161
+ - spec/models/page.rb
176
162
  - spec/mongoid-multitenancy_spec.rb
177
163
  - spec/spec_helper.rb
178
164
  has_rdoc: