acts_as_tenant 0.4.3 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +124 -25
  3. data/Rakefile +5 -3
  4. data/lib/acts_as_tenant/configuration.rb +6 -19
  5. data/lib/acts_as_tenant/controller_extensions/filter.rb +13 -0
  6. data/lib/acts_as_tenant/controller_extensions/subdomain.rb +20 -0
  7. data/lib/acts_as_tenant/controller_extensions/subdomain_or_domain.rb +20 -0
  8. data/lib/acts_as_tenant/controller_extensions.rb +10 -59
  9. data/lib/acts_as_tenant/errors.rb +3 -4
  10. data/lib/acts_as_tenant/model_extensions.rb +59 -136
  11. data/lib/acts_as_tenant/sidekiq.rb +11 -7
  12. data/lib/acts_as_tenant/tenant_helper.rb +7 -0
  13. data/lib/acts_as_tenant/test_tenant_middleware.rb +15 -0
  14. data/lib/acts_as_tenant/version.rb +1 -1
  15. data/lib/acts_as_tenant.rb +112 -14
  16. data/spec/acts_as_tenant/configuration_spec.rb +8 -19
  17. data/spec/acts_as_tenant/sidekiq_spec.rb +14 -19
  18. data/spec/{acts_as_tenant/tenant_by_filter_spec.rb → controllers/filter_spec.rb} +7 -12
  19. data/spec/controllers/subdomain_or_domain_spec.rb +55 -0
  20. data/spec/controllers/subdomain_spec.rb +49 -0
  21. data/spec/dummy/.ruby-version +1 -0
  22. data/spec/dummy/Rakefile +6 -0
  23. data/spec/dummy/app/assets/config/manifest.js +2 -0
  24. data/spec/dummy/app/assets/images/.keep +0 -0
  25. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  26. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  27. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  28. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  29. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  30. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  31. data/spec/dummy/app/javascript/packs/application.js +15 -0
  32. data/spec/dummy/app/jobs/application_job.rb +7 -0
  33. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  34. data/spec/dummy/app/mailers/user_mailer.rb +5 -0
  35. data/spec/dummy/app/models/account.rb +4 -0
  36. data/spec/dummy/app/models/aliased_task.rb +4 -0
  37. data/spec/dummy/app/models/article.rb +3 -0
  38. data/spec/dummy/app/models/comment.rb +5 -0
  39. data/spec/dummy/app/models/concerns/.keep +0 -0
  40. data/spec/dummy/app/models/custom_counter_cache_task.rb +4 -0
  41. data/spec/dummy/app/models/custom_foreign_key_task.rb +4 -0
  42. data/spec/dummy/app/models/custom_primary_key_task.rb +4 -0
  43. data/spec/dummy/app/models/global_project.rb +6 -0
  44. data/spec/dummy/app/models/global_project_with_conditions.rb +6 -0
  45. data/spec/dummy/app/models/global_project_with_if.rb +6 -0
  46. data/spec/dummy/app/models/manager.rb +4 -0
  47. data/spec/dummy/app/models/polymorphic_tenant_comment.rb +5 -0
  48. data/spec/dummy/app/models/project.rb +8 -0
  49. data/spec/dummy/app/models/task.rb +7 -0
  50. data/spec/dummy/app/models/unique_task.rb +5 -0
  51. data/spec/dummy/app/models/unscoped_model.rb +3 -0
  52. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  53. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  54. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  55. data/spec/dummy/bin/rails +4 -0
  56. data/spec/dummy/bin/rake +4 -0
  57. data/spec/dummy/bin/setup +33 -0
  58. data/spec/dummy/config/application.rb +19 -0
  59. data/spec/dummy/config/boot.rb +5 -0
  60. data/spec/dummy/config/cable.yml +10 -0
  61. data/spec/dummy/config/database.yml +19 -0
  62. data/spec/dummy/config/environment.rb +5 -0
  63. data/spec/dummy/config/environments/development.rb +62 -0
  64. data/spec/dummy/config/environments/production.rb +112 -0
  65. data/spec/dummy/config/environments/test.rb +49 -0
  66. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  67. data/spec/dummy/config/initializers/assets.rb +12 -0
  68. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  69. data/spec/dummy/config/initializers/content_security_policy.rb +28 -0
  70. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  71. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  72. data/spec/dummy/config/initializers/inflections.rb +16 -0
  73. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  74. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  75. data/spec/dummy/config/locales/en.yml +40 -0
  76. data/spec/dummy/config/puma.rb +38 -0
  77. data/spec/dummy/config/routes.rb +4 -0
  78. data/spec/dummy/config/spring.rb +6 -0
  79. data/spec/dummy/config/storage.yml +34 -0
  80. data/spec/dummy/config.ru +5 -0
  81. data/spec/dummy/db/schema.rb +84 -0
  82. data/spec/dummy/lib/assets/.keep +0 -0
  83. data/spec/dummy/log/.keep +0 -0
  84. data/spec/dummy/public/404.html +67 -0
  85. data/spec/dummy/public/422.html +67 -0
  86. data/spec/dummy/public/500.html +66 -0
  87. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  88. data/spec/dummy/public/apple-touch-icon.png +0 -0
  89. data/spec/dummy/public/favicon.ico +0 -0
  90. data/spec/dummy/tmp/development_secret.txt +1 -0
  91. data/spec/fixtures/accounts.yml +10 -0
  92. data/spec/fixtures/custom_primary_key_tasks.yml +2 -0
  93. data/spec/fixtures/global_projects.yml +13 -0
  94. data/spec/fixtures/projects.yml +10 -0
  95. data/spec/helpers/tenant_helper_spec.rb +16 -0
  96. data/spec/middlewares/test_tenant_middleware_spec.rb +86 -0
  97. data/spec/models/model_extensions_spec.rb +413 -0
  98. data/spec/spec_helper.rb +9 -13
  99. metadata +205 -41
  100. data/.gitignore +0 -7
  101. data/.travis.yml +0 -4
  102. data/CHANGELOG.md +0 -112
  103. data/Gemfile +0 -4
  104. data/_config.yml +0 -1
  105. data/acts_as_tenant.gemspec +0 -32
  106. data/docs/blog_post.md +0 -67
  107. data/rails/init.rb +0 -2
  108. data/spec/active_record_helper.rb +0 -22
  109. data/spec/active_record_models.rb +0 -116
  110. data/spec/acts_as_tenant/model_extensions_spec.rb +0 -420
  111. data/spec/acts_as_tenant/tenant_by_subdomain_or_domain.rb +0 -46
  112. data/spec/acts_as_tenant/tenant_by_subdomain_spec.rb +0 -32
  113. data/spec/database.yml +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 82220bfda9712aaff3d6d06aa5ddbd236290d861
4
- data.tar.gz: a2e325e8ed0ef37fb3a2bf0ab606eeede7e6907b
2
+ SHA256:
3
+ metadata.gz: b9dbb40015b39583a44c37496f0687641e1a66f9b70357260b1fcabe7f3c542d
4
+ data.tar.gz: 88d1ce36220fd3c8e8264b95d76afb7f883cc77da0ac9f12538cde682fa9dacf
5
5
  SHA512:
6
- metadata.gz: e64518b47c7500dad952b6ffe4f1faf5b5d23965fd997fa98bef9a5fd9abd33613dac5b743d8aaec146495d615998d7677d67112efc69387e6d76397e83b1683
7
- data.tar.gz: 535154c7c6ac8e4044fbdc989b931e78fc307027aa154e8b14fc63abd658b76d418d19c0abfbbff3265add12a2a1b861a22fa66f03c89ff419ac1870648ce233
6
+ metadata.gz: 7d76fbf4cc3381afdfa2c02627ad6de56ff9e4cdaa636da4103e11e38ee48a6f6ecf3f432f296bfd3b8ae5cfc690d8fc52cbc7e025953e39cf3b3dab4439d3f1
7
+ data.tar.gz: ba09cb46b06f2399de2ac2e4d6efa3369d22e287a6741bfd0fcfc483836b64ac96851dd671dd4a97bace409c7aa72f6e7fc03394250f853c55a54159e720118a
data/README.md CHANGED
@@ -1,9 +1,8 @@
1
- Acts As Tenant
2
- ==============
1
+ # Acts As Tenant
3
2
 
4
- [![Build Status](https://travis-ci.org/ErwinM/acts_as_tenant.svg)](https://travis-ci.org/ErwinM/acts_as_tenant)
3
+ [![Build Status](https://github.com/ErwinM/acts_as_tenant/workflows/Tests/badge.svg)](https://github.com/ErwinM/acts_as_tenant/actions) [![Gem Version](https://badge.fury.io/rb/acts_as_tenant.svg)](https://badge.fury.io/rb/acts_as_tenant)
5
4
 
6
- **Note**: acts_as_tenant was introduced in this [blog post](https://github.com/ErwinM/acts_as_tenant/blob/master/docs/blog_post.md).
5
+ Row-level multitenancy for Ruby on Rails apps.
7
6
 
8
7
  This gem was born out of our own need for a fail-safe and out-of-the-way manner to add multi-tenancy to our Rails app through a shared database strategy, that integrates (near) seamless with Rails.
9
8
 
@@ -16,9 +15,27 @@ In addition, acts_as_tenant:
16
15
  * adds a method to validate uniqueness to a tenant, `validates_uniqueness_to_tenant`
17
16
  * sets up a helper method containing the current tenant
18
17
 
18
+ **Note**: acts_as_tenant was introduced in this [blog post](https://github.com/ErwinM/acts_as_tenant/blob/master/docs/blog_post.md).
19
+
20
+ **Row-level vs schema multitenancy**
21
+
22
+ What's the difference?
23
+
24
+ Row-level multitenancy each model must have a tenant ID column on it. This makes it easy to filter records for each tenant using your standard database columns and indexes. ActsAsTenant uses row-level multitenancy.
25
+
26
+ Schema multitenancy uses database schemas to handle multitenancy. For this approach, your database has multiple schemas and each schema contains your database tables. Schemas require migrations to be run against each tenant and generally makes it harder to scale as you add more tenants. The Apartment gem uses schema multitenancy.
27
+
28
+ #### 🎬 Walkthrough
29
+
30
+ Want to see how it works? Check out [the ActsAsTenant walkthrough video](https://www.youtube.com/watch?v=BIyxM9f8Jus):
31
+
32
+ <a href="https://www.youtube.com/watch?v=BIyxM9f8Jus">
33
+ <img src="https://i.imgur.com/DLRPzhv.png" width="300" height="auto" alt="ActsAsTenant Walkthrough Video">
34
+ </a>
35
+
19
36
  Installation
20
37
  ------------
21
- acts_as_tenant will only work on Rails 3.1 and up. This is due to changes made to the handling of `default_scope`, an essential pillar of the gem.
38
+ acts_as_tenant will only work on Rails 5.2 and up. This is due to changes made to the handling of `default_scope`, an essential pillar of the gem.
22
39
 
23
40
  To use it, add it to your Gemfile:
24
41
 
@@ -41,7 +58,8 @@ There are three ways to set the current tenant:
41
58
  2. by setting the current tenant in the controller, and
42
59
  3. by setting the current tenant for a block.
43
60
 
44
- ### Use the subdomain to lookup the current tenant ###
61
+ ### Looking Up Tenants
62
+ #### By Subdomain to lookup the current tenant
45
63
 
46
64
  ```ruby
47
65
  class ApplicationController < ActionController::Base
@@ -49,11 +67,23 @@ class ApplicationController < ActionController::Base
49
67
  end
50
68
  ```
51
69
 
52
- This tells acts_as_tenant to use the current subdomain to identify the current tenant. In addition, it tells acts_as_tenant that tenants are represented by the Account model and this model has a column named 'subdomain' which can be used to lookup the Account using the actual subdomain. If ommitted, the parameters will default to the values used above.
70
+ This tells acts_as_tenant to use the last subdomain to identify the current tenant. In addition, it tells acts_as_tenant that tenants are represented by the Account model and this model has a column named 'subdomain' which can be used to lookup the Account using the actual subdomain. If ommitted, the parameters will default to the values used above.
71
+
72
+ By default, the *last* subdomain will be used for lookup. Pass in `subdomain_lookup: :first` to use the first subdomain instead.
73
+
74
+ #### By Domain to lookup the current tenant
75
+
76
+ ```ruby
77
+ class ApplicationController < ActionController::Base
78
+ set_current_tenant_by_subdomain_or_domain(:account, :subdomain, :domain)
79
+ end
80
+ ```
81
+
82
+ You can locate the tenant using `set_current_tenant_by_subdomain_or_domain( :account, :subdomain, :domain )` which will check for a subdomain and fallback to domain.
53
83
 
54
- Alternatively, you could locate the tenant using the method `set_current_tenant_by_subdomain_or_domain( :account, :subdomain, :domain )` which will try to match a record first by subdomain. in case it fails, by domain.
84
+ By default, the *last* subdomain will be used for lookup. Pass in `subdomain_lookup: :first` to use the first subdomain instead.
55
85
 
56
- ### Setting the current tenant in a controller, manually ###
86
+ #### Manually using before_action
57
87
 
58
88
  ```ruby
59
89
  class ApplicationController < ActionController::Base
@@ -69,6 +99,21 @@ end
69
99
 
70
100
  Setting the `current_tenant` yourself, requires you to declare `set_current_tenant_through_filter` at the top of your application_controller to tell acts_as_tenant that you are going to use a before_action to setup the current tenant. Next you should actually setup that before_action to fetch the current tenant and pass it to `acts_as_tenant` by using `set_current_tenant(current_tenant)` in the before_action.
71
101
 
102
+ If you are setting the tenant in a specific controller (except `application_controller`), it should to be included **AT THE TOP** of the file.
103
+
104
+ ```
105
+ class MembersController < ActionController::Base
106
+ set_current_tenant_through_filter
107
+ before_action :set_tenant
108
+ before_action :set_member, only: [:show, :edit, :update, :destroy]
109
+
110
+ def set_tenant
111
+ set_current_tenant(current_user.account)
112
+ end
113
+ end
114
+ ```
115
+
116
+ This allows the tenant to be set before any other code runs so everything is within the current tenant.
72
117
 
73
118
  ### Setting the current tenant for a block ###
74
119
 
@@ -94,7 +139,7 @@ This is useful in shared routes such as admin panels or internal dashboards when
94
139
 
95
140
  ### Require tenant to be set always ###
96
141
 
97
- If you want to require the tenant to be set at all times, you can configure acts_as_tenant to raise an error when a query is made without a tenant available. See below under configuarion options.
142
+ If you want to require the tenant to be set at all times, you can configure acts_as_tenant to raise an error when a query is made without a tenant available. See below under configuration options.
98
143
 
99
144
  Scoping your models
100
145
  -------------------
@@ -151,10 +196,18 @@ All options available to Rails' own `validates_uniqueness_of` are also available
151
196
 
152
197
  ### Custom foreign_key ###
153
198
 
154
- You can explicitely specifiy a foreign_key for AaT to use should the key differ from the default:
199
+ You can explicitly specifiy a foreign_key for AaT to use should the key differ from the default:
155
200
 
156
201
  ```ruby
157
- acts_as_tenant(:account, :foreign_key => 'accountID) # by default AaT expects account_id
202
+ acts_as_tenant(:account, :foreign_key => 'accountID') # by default AaT expects account_id
203
+ ```
204
+
205
+ ### Custom primary_key ###
206
+
207
+ You can also explicitly specifiy a primary_key for AaT to use should the key differ from the default:
208
+
209
+ ```ruby
210
+ acts_as_tenant(:account, :primary_key => 'primaryID') # by default AaT expects id
158
211
  ```
159
212
 
160
213
  Configuration options
@@ -170,6 +223,23 @@ end
170
223
 
171
224
  * `config.require_tenant` when set to true will raise an ActsAsTenant::NoTenant error whenever a query is made without a tenant set.
172
225
 
226
+ belongs_to options
227
+ ---------------------
228
+ `acts_as_tenant :account` includes the belongs_to relationship.
229
+ So when using acts_as_tenant on a model, do not add `belongs_to :account` alongside `acts_as_tenant :account`:
230
+
231
+ ```
232
+ class User < ActiveRecord::Base
233
+ acts_as_tenant(:account) # YES
234
+ belongs_to :account # REDUNDANT
235
+ end
236
+ ```
237
+
238
+ You can add the following `belongs_to` options to `acts_as_tenant`:
239
+ `:foreign_key, :class_name, :inverse_of, :optional, :primary_key, :counter_cache`
240
+
241
+ Example: `acts_as_tenant(:account, counter_cache: true)`
242
+
173
243
  Sidekiq support
174
244
  ---------------
175
245
 
@@ -183,24 +253,42 @@ require 'acts_as_tenant/sidekiq'
183
253
  Testing
184
254
  ---------------
185
255
 
186
- If you set the `current_tenant` in your tests, make sure to clean up the tenant after each test by calling `ActsAsTenant.current_tenant = nil`. If you are manually setting the `current_tenant` in integration tests, please be aware that the value will not survive across multiple requests, even if they take place within the same test.
256
+ If you set the `current_tenant` in your tests, make sure to clean up the tenant after each test by calling `ActsAsTenant.current_tenant = nil`. Integration tests are more difficult: manually setting the `current_tenant` value will not survive across multiple requests, even if they take place within the same test. This can result in undesired boilerplate to set the desired tenant. Moreover, the efficacy of the test can be compromised because the set `current_tenant` value will carry over into the request-response cycle.
187
257
 
188
- If you'd like to set a default tenant that will survive across multiple requests, assign a value to `default_tenant`. You might use a before hook like this:
258
+ To address this issue, ActsAsTenant provides for a `test_tenant` value that can be set to allow for setup and post-request expectation testing. It should be used in conjunction with middleware that clears out this value while an integration test is processing. A typical Rails and RSpec setup might look like:
189
259
 
190
260
  ```ruby
191
- # Make the default tenant globally available to the tests
192
- $default_account = Account.create!
193
- # Specify this account as the current tenant unless overridden
194
- ActsAsTenant.default_tenant = $default_account
195
- # Stub out the method setting a tenant in a controller hook
196
- allow_any_instance_of(ApplicationController).to receive(:set_current_tenant)
261
+ # test.rb
262
+ require_dependency 'acts_as_tenant/test_tenant_middleware'
263
+
264
+ Rails.application.configure do
265
+ config.middleware.use ActsAsTenant::TestTenantMiddleware
266
+ end
197
267
  ```
198
268
 
199
- This can later be overridden by using any of the standard methods for specifying a different tenant. If you don't want this setting to apply to all of your tests, remember to clear it when you're finished by setting `ActsAsTenant.default_tenant = nil`.
269
+ ```ruby
270
+ # spec_helper.rb
271
+ config.before(:suite) do |example|
272
+ # Make the default tenant globally available to the tests
273
+ $default_account = Account.create!
274
+ end
200
275
 
201
- To Do
202
- -----
203
- * ...
276
+ config.before(:each) do |example|
277
+ if example.metadata[:type] == :request
278
+ # Set the `test_tenant` value for integration tests
279
+ ActsAsTenant.test_tenant = $default_account
280
+ else
281
+ # Otherwise just use current_tenant
282
+ ActsAsTenant.current_tenant = $default_account
283
+ end
284
+ end
285
+
286
+ config.after(:each) do |example|
287
+ # Clear any tenancy that might have been set
288
+ ActsAsTenant.current_tenant = nil
289
+ ActsAsTenant.test_tenant = nil
290
+ end
291
+ ```
204
292
 
205
293
  Bug reports & suggested improvements
206
294
  ------------------------------------
@@ -210,9 +298,20 @@ If you have found a bug or want to suggest an improvement, please use our issue
210
298
 
211
299
  If you want to contribute, fork the project, code your improvements and make a pull request on [Github](http://github.com/ErwinM/acts_as_tenant/). When doing so, please don't forget to add tests. If your contribution is fixing a bug it would be perfect if you could also submit a failing test, illustrating the issue.
212
300
 
301
+ Contributing to this gem
302
+ ------------------------
303
+
304
+ We use the Appraisal gem to run tests against supported versions of Rails to test for compatibility against them all. StandardRb also helps keep code formatted cleanly.
305
+
306
+ 1. Fork the repo
307
+ 2. Make changes
308
+ 3. Run test suite with `bundle exec appraisal`
309
+ 4. Run `bundle exec standardrb` to standardize code formatting
310
+ 5. Submit a PR
311
+
213
312
  Author & Credits
214
313
  ----------------
215
- acts_as_tenant is written by Erwin Matthijssen.
314
+ acts_as_tenant is written by Erwin Matthijssen & Chris Oliver.
216
315
 
217
316
  This gem was inspired by Ryan Sonnek's [Multitenant](https://github.com/wireframe/multitenant) gem and its use of default_scope.
218
317
 
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
- require 'bundler/gem_tasks'
1
+ require "bundler/gem_tasks"
2
2
 
3
- require 'rspec/core/rake_task'
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
+
5
+ require "rspec/core/rake_task"
4
6
  RSpec::Core::RakeTask.new(:spec)
5
- task :default => :spec
7
+ task default: :spec
@@ -1,26 +1,13 @@
1
1
  module ActsAsTenant
2
- @@configuration = nil
3
-
4
- def self.configure
5
- @@configuration = Configuration.new
6
-
7
- if block_given?
8
- yield configuration
9
- end
10
-
11
- configuration
12
- end
13
-
14
- def self.configuration
15
- @@configuration || configure
16
- end
17
-
18
2
  class Configuration
19
- attr_writer :require_tenant
20
-
3
+ attr_writer :require_tenant, :pkey
4
+
21
5
  def require_tenant
22
6
  @require_tenant ||= false
23
7
  end
24
-
8
+
9
+ def pkey
10
+ @pkey ||= :id
11
+ end
25
12
  end
26
13
  end
@@ -0,0 +1,13 @@
1
+ module ActsAsTenant
2
+ module ControllerExtensions
3
+ module Filter
4
+ extend ActiveSupport::Concern
5
+
6
+ private
7
+
8
+ def set_current_tenant(current_tenant_object)
9
+ ActsAsTenant.current_tenant = current_tenant_object
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ module ActsAsTenant
2
+ module ControllerExtensions
3
+ module Subdomain
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ cattr_accessor :tenant_class, :tenant_column, :subdomain_lookup
8
+ before_action :find_tenant_by_subdomain
9
+ end
10
+
11
+ private
12
+
13
+ def find_tenant_by_subdomain
14
+ if (subdomain = request.subdomains.send(subdomain_lookup))
15
+ ActsAsTenant.current_tenant = tenant_class.where(tenant_column => subdomain.downcase).first
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module ActsAsTenant
2
+ module ControllerExtensions
3
+ module SubdomainOrDomain
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ cattr_accessor :tenant_class, :tenant_primary_column, :tenant_second_column, :subdomain_lookup
8
+ before_action :find_tenant_by_subdomain_or_domain
9
+ end
10
+
11
+ private
12
+
13
+ def find_tenant_by_subdomain_or_domain
14
+ subdomain = request.subdomains.send(subdomain_lookup)
15
+ query = subdomain.present? ? {tenant_primary_column => subdomain.downcase} : {tenant_second_column => request.domain.downcase}
16
+ ActsAsTenant.current_tenant = tenant_class.where(query).first
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,85 +1,36 @@
1
1
  module ActsAsTenant
2
2
  module ControllerExtensions
3
+ autoload :Filter, "acts_as_tenant/controller_extensions/filter"
4
+ autoload :Subdomain, "acts_as_tenant/controller_extensions/subdomain"
5
+ autoload :SubdomainOrDomain, "acts_as_tenant/controller_extensions/subdomain_or_domain"
3
6
 
4
7
  # this method allows setting the current_tenant by reading the subdomain and looking
5
8
  # it up in the tenant-model passed to the method. The method will look for the subdomain
6
9
  # in a column referenced by the second argument.
7
- def set_current_tenant_by_subdomain(tenant = :account, column = :subdomain )
8
- self.class_eval do
9
- cattr_accessor :tenant_class, :tenant_column
10
- end
10
+ def set_current_tenant_by_subdomain(tenant = :account, column = :subdomain, subdomain_lookup: :last)
11
+ include Subdomain
11
12
 
12
13
  self.tenant_class = tenant.to_s.camelcase.constantize
13
14
  self.tenant_column = column.to_sym
14
-
15
- self.class_eval do
16
-
17
- before_action :find_tenant_by_subdomain
18
- helper_method :current_tenant if respond_to?(:helper_method)
19
-
20
-
21
- private
22
- def find_tenant_by_subdomain
23
- if request.subdomains.last
24
- ActsAsTenant.current_tenant = tenant_class.where(tenant_column => request.subdomains.last.downcase).first
25
- end
26
- end
27
-
28
- def current_tenant
29
- ActsAsTenant.current_tenant
30
- end
31
- end
15
+ self.subdomain_lookup = subdomain_lookup
32
16
  end
33
17
 
34
18
  # 01/27/2014 Christian Yerena / @preth00nker
35
19
  # this method adds the possibility of use the domain as a possible second argument to find
36
20
  # the current_tenant.
37
- def set_current_tenant_by_subdomain_or_domain(tenant = :account, primary_column = :subdomain, second_column = :domain )
38
- self.class_eval do
39
- cattr_accessor :tenant_class, :tenant_primary_column, :tenant_second_column
40
- end
21
+ def set_current_tenant_by_subdomain_or_domain(tenant = :account, primary_column = :subdomain, second_column = :domain, subdomain_lookup: :last)
22
+ include SubdomainOrDomain
41
23
 
42
24
  self.tenant_class = tenant.to_s.camelcase.constantize
43
25
  self.tenant_primary_column = primary_column.to_sym
44
26
  self.tenant_second_column = second_column.to_sym
45
-
46
- self.class_eval do
47
-
48
- before_action :find_tenant_by_subdomain_or_domain
49
- helper_method :current_tenant if respond_to?(:helper_method)
50
-
51
-
52
- private
53
- def find_tenant_by_subdomain_or_domain
54
- if request.subdomains.last
55
- ActsAsTenant.current_tenant = tenant_class.where(tenant_primary_column => request.subdomains.last.downcase).first
56
- else
57
- ActsAsTenant.current_tenant = tenant_class.where(tenant_second_column => request.domain.downcase).first
58
- end
59
- end
60
-
61
- def current_tenant
62
- ActsAsTenant.current_tenant
63
- end
64
- end
27
+ self.subdomain_lookup = subdomain_lookup
65
28
  end
66
29
 
67
-
68
30
  # This method sets up a method that allows manual setting of the current_tenant. This method should
69
31
  # be used in a before_action. In addition, a helper is setup that returns the current_tenant
70
32
  def set_current_tenant_through_filter
71
- self.class_eval do
72
- helper_method :current_tenant if respond_to?(:helper_method)
73
-
74
- private
75
- def set_current_tenant(current_tenant_object)
76
- ActsAsTenant.current_tenant = current_tenant_object
77
- end
78
-
79
- def current_tenant
80
- ActsAsTenant.current_tenant
81
- end
82
- end
33
+ include Filter
83
34
  end
84
35
  end
85
36
  end
@@ -5,15 +5,14 @@ module ActsAsTenant
5
5
  module Errors
6
6
  class ModelNotScopedByTenant < ActsAsTenant::Error
7
7
  end
8
-
8
+
9
9
  class NoTenantSet < ActsAsTenant::Error
10
10
  end
11
-
11
+
12
12
  class ModelNotScopedByTenant < ActsAsTenant::Error
13
13
  end
14
-
14
+
15
15
  class TenantIsImmutable < ActsAsTenant::Error
16
16
  end
17
-
18
17
  end
19
18
  end