mongoid-multitenancy 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YjY1NTgwNWVlNWJhZWQ5NGI2MjVkZmZlMTY0ZWIyMjUyZDg3ZTdlNw==
4
+ Njk4YWRlMTZhYzljNjc2ZjBiNjQwYWY1YmQ4NjAzMWM2OTIzZGExYw==
5
5
  data.tar.gz: !binary |-
6
- YjFhODhkYjZiNTUwZDczYjA3NGZhMTViNDhkY2I3MWU1MTE1ODJhZA==
6
+ NjcwYzEwZDNiYTlhODBiMWExNjY5MGVjOWI3ZTQ5MmQwM2Q2OWNiMQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- M2U5YjM5MWE0YWZjMWJiOTc0YzE3YmQ4ZDljNzgwYjc5YzE0YTRhMzczZmUy
10
- YzBjMDJmYTNjY2FjMjBiNDljYTRlNDRiYTg1YTM0NjUzOGVmNjJmMjkyYzdh
11
- N2NhMDcwMjI4MDc2MjJkOGJhMTEwNTg4ZGMzYTNkMjE2ZmQ4N2Q=
9
+ NzFmNjU1ODg0MzE0YzE4ODE0YTViODVhMGEzZWMyOGViZjBkNTg5MDg4ZWU4
10
+ M2ViY2MxMzE0YmU1MDY5NTAxNGQxN2NiOTJkNjg2NzM2ODA0ODMyYjJjYWM4
11
+ NmMyY2NjMzljMGJlY2VkNzMyYzA3OTJmYzk2NTY1ODhjOTllZWM=
12
12
  data.tar.gz: !binary |-
13
- ODMwMDVjOTc4YTFiN2E2ZWQ5ODhlNmM1NTgyYWQ1MmEyMjI0ZTQwZmRlNjhj
14
- NTMyY2U2YzE1N2U1MDNhM2I2MjdhMjhmOWRlZGJjM2U1ZWQyOGE0MTM4NmY3
15
- NWY2MTdkMjY0M2EyZmY1YmFjZmYzMTk4MDA3MzlkNmEyM2FjYzQ=
13
+ M2RiMmYxZGU5NWE5MGZjNzkxZTljNjU1ZjVjM2U1ZGM2Yzg3ZmRkYjhkYTBh
14
+ YzZkZTYyMjJjYjRmZWUwOTdmNGU2M2U2NTVmMjY5MTJjODE4Mzg1NmIzMDA4
15
+ YTQzZWZjMTAyYzAwYWExZWQ1NGNhODFlOGQ1NTExOTBiYzQzZmE=
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mongoid-multitenancy (0.2.0)
4
+ mongoid-multitenancy (0.3)
5
5
  mongoid (~> 3)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -8,7 +8,8 @@ In addition, mongoid-multitenancy:
8
8
 
9
9
  * allows you to set the current tenant
10
10
  * redefines some mongoid functions like `index`, `validates_with` and `delete_all` to take in account the multitenancy
11
- * makes the tenant field immutable once it is persisted
11
+ * allows shared items between the tenants
12
+ * allows you to define an immutable tenant field once it is persisted
12
13
  * is thread safe.
13
14
 
14
15
  Installation
@@ -40,15 +41,19 @@ There are two ways to set the current tenant: (1) by setting the current tenant
40
41
 
41
42
  **Setting the current tenant in a controller, manually**
42
43
 
43
- Mongoid::Multitenancy.current_tenant = client_instance
44
+ ```ruby
45
+ Mongoid::Multitenancy.current_tenant = client_instance
46
+ ```
44
47
 
45
48
  Setting the current_tenant yourself requires you to use a before_filter to set the Mongoid::Multitenancy.current_tenant variable.
46
49
 
47
50
  **Setting the current tenant for a block**
48
51
 
49
- Mongoid::Multitenancy.with_tenant(client_instance) do
50
- # Current tenant is set for all code in this block
51
- end
52
+ ```ruby
53
+ Mongoid::Multitenancy.with_tenant(client_instance) do
54
+ # Current tenant is set for all code in this block
55
+ end
56
+ ```
52
57
 
53
58
  This approach is useful when running background processes for a specified tenant. For example, by putting this in your worker's run method,
54
59
  any code in this block will be scoped to the current tenant. All methods that set the current tenant are thread safe.
@@ -57,51 +62,58 @@ any code in this block will be scoped to the current tenant. All methods that se
57
62
 
58
63
  Scoping your models
59
64
  -------------------
60
- class Client
61
- include Mongoid::Document
65
+ ```ruby
66
+ class Client
67
+ include Mongoid::Document
62
68
 
63
- field :name, :type => String
64
- validates_uniqueness_of :name
65
- end
69
+ field :name, :type => String
70
+ validates_uniqueness_of :name
71
+ end
66
72
 
67
- class Article
68
- include Mongoid::Document
69
- include Mongoid::Multitenancy::Document
73
+ class Article
74
+ include Mongoid::Document
75
+ include Mongoid::Multitenancy::Document
70
76
 
71
- tenant(:client)
77
+ tenant(:client)
72
78
 
73
- field :title, :type => String
74
- end
79
+ field :title, :type => String
80
+ end
81
+ ```
75
82
 
76
83
  Adding `tenant` to your model declaration will scope that model to the current tenant **BUT ONLY if a current tenant has been set**.
77
84
  The association passed to the `tenant` function must be valid.
78
85
 
79
86
  `tenant` accepts several options:
80
87
 
81
- * :optional : set to true when the tenant can be optional
88
+ * :optional : set to true when the tenant is optional (default value is `false`)
89
+ * :immutable : set to true when the tenant field is immutable (default value is `true`)
82
90
  * :class_name, etc. : all the other options will be passed to the mongoid relation
83
91
 
84
92
  Some examples to illustrate this behavior:
85
93
 
86
- # This manually sets the current tenant for testing purposes. In your app this is handled by the gem.
87
- Mongoid::Multitenancy.current_tenant = Client.find_by(:name => 'Perfect Memory') # => <#Client _id:50ca04b86c82bfc125000025, :name: "Perfect Memory">
94
+ ```ruby
95
+ # This manually sets the current tenant for testing purposes. In your app this is handled by the gem.
96
+ Mongoid::Multitenancy.current_tenant = Client.find_by(:name => 'Perfect Memory') # => <#Client _id:50ca04b86c82bfc125000025, :name: "Perfect Memory">
88
97
 
89
- # All searches are scoped by the tenant, the following searches will only return objects belonging to the current client.
90
- Article.all # => all articles where client_id => 50ca04b86c82bfc125000025
98
+ # All searches are scoped by the tenant, the following searches will only return objects belonging to the current client.
99
+ Article.all # => all articles where client_id => 50ca04b86c82bfc125000025
91
100
 
92
- # New objects are scoped to the current tenant
93
- Article.new(:title => 'New blog') # => <#Article _id: nil, title: 'New blog', :client_id: 50ca04b86c82bfc125000025>
101
+ # New objects are scoped to the current tenant
102
+ Article.new(:title => 'New blog') # => <#Article _id: nil, title: 'New blog', :client_id: 50ca04b86c82bfc125000025>
94
103
 
95
- # It makes the tenant field immutable once it is persisted to avoid inconsistency
96
- article.persisted? # => true
97
- article.client = another_client
98
- article.valid? # => false
104
+ # It can make the tenant field immutable once it is persisted to avoid inconsistency
105
+ article.persisted? # => true
106
+ article.client = another_client
107
+ article.valid? # => false
108
+ ```
99
109
 
100
110
  **Optional tenant**
101
111
 
102
112
  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
113
 
104
- Article.all # => all articles where client_id.in [50ca04b86c82bfc125000025, nil]
114
+ ```ruby
115
+ Article.all # => all articles where client_id.in [50ca04b86c82bfc125000025, nil]
116
+ ```
105
117
 
106
118
  Rails
107
119
  -------------------
@@ -110,14 +122,16 @@ If you are using Rails, you may want to set the current tenant at each request.
110
122
 
111
123
  **Manually set the current tenant in ApplicationController using the host request**
112
124
 
113
- class ApplicationController < ActionController::Base
114
- before_filter :set_current_client
125
+ ```ruby
126
+ class ApplicationController < ActionController::Base
127
+ before_filter :set_current_client
115
128
 
116
- def set_current_client
117
- current_client = Client.find_by_host(request.host)
118
- Mongoid::Multitenancy.current_tenant = current_client
119
- end
120
- end
129
+ def set_current_client
130
+ current_client = Client.find_by_host(request.host)
131
+ Mongoid::Multitenancy.current_tenant = current_client
132
+ end
133
+ end
134
+ ```
121
135
 
122
136
  Setting the current_tenant yourself requires you to use a before_filter to set the Mongoid::Multitenancy.current_tenant variable.
123
137
 
@@ -127,32 +141,36 @@ Mongoid Uniqueness validators
127
141
  mongoid-multitenancy will automatically add the tenant foreign key in the scope list for each of uniqueness validators in order
128
142
  to avoid to redefine all your validators.
129
143
 
130
- class Article
131
- include Mongoid::Document
132
- include Mongoid::Multitenancy::Document
144
+ ```ruby
145
+ class Article
146
+ include Mongoid::Document
147
+ include Mongoid::Multitenancy::Document
133
148
 
134
- tenant(:client)
149
+ tenant(:client)
135
150
 
136
- field :slug
151
+ field :slug
137
152
 
138
- validates_uniqueness_of :slug # => :scope => client_id is added automatically
139
- end
153
+ validates_uniqueness_of :slug # => :scope => client_id is added automatically
154
+ end
155
+ ```
140
156
 
141
157
  Mongoid indexes
142
158
  -------------------
143
159
 
144
160
  mongoid-multitenancy will automatically add the tenant foreign key in all your mongoid indexes to avoid to redefine all your validators.
145
161
 
146
- class Article
147
- include Mongoid::Document
148
- include Mongoid::Multitenancy::Document
162
+ ```ruby
163
+ class Article
164
+ include Mongoid::Document
165
+ include Mongoid::Multitenancy::Document
149
166
 
150
- tenant(:client)
167
+ tenant(:client)
151
168
 
152
- field :title
169
+ field :title
153
170
 
154
- index({ :title => 1 }) # => create an index with { :client_id => 1, :title => 1 }
155
- end
171
+ index({ :title => 1 }) # => create an index with { :client_id => 1, :title => 1 }
172
+ end
173
+ ```
156
174
 
157
175
  Author & Credits
158
176
  ----------------
@@ -21,7 +21,7 @@ module Mongoid
21
21
  attr_reader :tenant_field, :tenant_options
22
22
 
23
23
  def tenant(association = :account, options={})
24
- @tenant_options = { optional: options.delete(:optional) }
24
+ @tenant_options = { optional: options.delete(:optional), immutable: options.delete(:immutable) { true } }
25
25
  # Setup the association between the class and the tenant class
26
26
  # TODO: should index this association if no other indexes are defined => , index: true
27
27
  belongs_to association, options
@@ -42,7 +42,7 @@ module Mongoid
42
42
  }
43
43
 
44
44
  # Rewrite accessors to make tenant foreign_key/association immutable
45
- validate :check_tenant_immutability, :on => :update
45
+ validate :check_tenant_immutability, :on => :update if @tenant_options[:immutable]
46
46
 
47
47
  # Set the default_scope to scope to current tenant
48
48
  default_scope lambda {
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Multitenancy
3
- VERSION = "0.2"
3
+ VERSION = "0.3"
4
4
  end
5
5
  end
@@ -2,7 +2,7 @@ class Article
2
2
  include Mongoid::Document
3
3
  include Mongoid::Multitenancy::Document
4
4
 
5
- tenant(:client, :class_name => 'Account')
5
+ tenant(:client, :class_name => 'Account', :immutable => false)
6
6
 
7
7
  field :slug, :type => String
8
8
  field :title, :type => String
data/spec/models/page.rb CHANGED
@@ -2,7 +2,7 @@ class Page
2
2
  include Mongoid::Document
3
3
  include Mongoid::Multitenancy::Document
4
4
 
5
- tenant(:client, :class_name => 'Account', :optional => true)
5
+ tenant(:client, :class_name => 'Account', :optional => true )
6
6
 
7
7
  field :slug, :type => String
8
8
  field :title, :type => String
@@ -136,20 +136,41 @@ describe Article do
136
136
  before { Mongoid::Multitenancy.current_tenant = client }
137
137
  after { Mongoid::Multitenancy.current_tenant = nil }
138
138
 
139
- let(:article) { Article.create!(:title => "title X", :slug => "article-x") }
139
+ context "with :immutable" do
140
+ let(:item) { Page.create!(:title => "title X", :slug => "article-x") }
141
+
142
+ context "when the tenant has not changed" do
143
+ it 'should be valid' do
144
+ item.title = "title X (2)"
145
+ item.should be_valid
146
+ end
147
+ end
140
148
 
141
- context "when the tenant has not changed" do
142
- it 'should be valid' do
143
- article.title = "title X (2)"
144
- article.should be_valid
149
+ context "when the tenant has changed" do
150
+ it 'should be invalid' do
151
+ item.title = "title X (2)"
152
+ item.client = another_client
153
+ item.should_not be_valid
154
+ end
145
155
  end
146
156
  end
147
157
 
148
- context "when the tenant has changed" do
149
- it 'should be invalid' do
150
- article.title = "title X (2)"
151
- article.client = another_client
152
- article.should_not be_valid
158
+ context "without :immutable" do
159
+ let(:item) { Article.create!(:title => "title X", :slug => "article-x") }
160
+
161
+ context "when the tenant has not changed" do
162
+ it 'should be valid' do
163
+ item.title = "title X (2)"
164
+ item.should be_valid
165
+ end
166
+ end
167
+
168
+ context "when the tenant has changed" do
169
+ it 'should be valid' do
170
+ item.title = "title X (2)"
171
+ item.client = another_client
172
+ item.should be_valid
173
+ end
153
174
  end
154
175
  end
155
176
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-multitenancy
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aymeric Brisse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-16 00:00:00.000000000 Z
11
+ date: 2013-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mongoid