acts_as_tenant 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 215e3c4bffac36cc0e111df4d91ce5d48cd9180b
4
- data.tar.gz: 4cc15333e4bb02df2708e6e1b65d8b1d62fe0732
3
+ metadata.gz: abc77aadd13ef4f32cbbbe8af35e7d48177b6cba
4
+ data.tar.gz: 0f151185b5ff68073c2bc85655e3972907453482
5
5
  SHA512:
6
- metadata.gz: 13089890ed6915b0cac19a818ca3d45d30e3e24c4534aa238a3f039674f1d375508534271b919c31aa142ed3871afde6c1796ea5123e3acf1db6c50dc67eb567
7
- data.tar.gz: 444740576efaca0fd486d3a8ab8d72b39f33122dbbec9cf18f40a7f16089cb97c2107624e1d131b6df27190f7c89ab006b83e1cd58dcec216380698b4bfdcc0a
6
+ metadata.gz: '087f67e11e1cb133274eaa45ce505c0b535df937e8f49149e898f83eb92e69f321ce0ab58d36a8ea5aa36d38e5b6a5bf637a56c71a872effeda875dc707576f2'
7
+ data.tar.gz: 60b79f39295a57bee878532cb697ac8b5570afed65bc9ffeb01a0daa80167f2c074788e1a46855ed321d12aae18135f237ef86de360b30c58728e0f1966dcdb1
@@ -1,3 +1,5 @@
1
+ * Replace all `before_filter` with `before_action` for Rails 5.1 compatibility
2
+
1
3
  0.4.1
2
4
  ------
3
5
  * Removed (stale, no longer working) MongoDB support; moved code to separate branch
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  Acts As Tenant
2
2
  ==============
3
3
 
4
- [![Build Status](https://travis-ci.org/ErwinM/acts_as_tenant.png)](https://travis-ci.org/ErwinM/acts_as_tenant)
4
+ [![Build Status](https://travis-ci.org/ErwinM/acts_as_tenant.svg)](https://travis-ci.org/ErwinM/acts_as_tenant)
5
5
 
6
- **Note**: acts_as_tenant was introduced in this [blog post](http://www.rollcallapp.com/blog/2011/10/03/adding-multi-tenancy-to-your-rails-app-acts-as-tenant).
6
+ **Note**: acts_as_tenant was introduced in this [blog post](https://github.com/ErwinM/acts_as_tenant/blob/master/docs/blog_post.md).
7
7
 
8
8
  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
9
 
@@ -58,7 +58,7 @@ Alternatively, you could locate the tenant using the method `set_current_tenant_
58
58
  ```ruby
59
59
  class ApplicationController < ActionController::Base
60
60
  set_current_tenant_through_filter
61
- before_filter :your_method_that_finds_the_current_tenant
61
+ before_action :your_method_that_finds_the_current_tenant
62
62
 
63
63
  def your_method_that_finds_the_current_tenant
64
64
  current_account = Account.find_it
@@ -67,7 +67,7 @@ class ApplicationController < ActionController::Base
67
67
  end
68
68
  ```
69
69
 
70
- 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_filter to setup the current tenant. Next you should actually setup that before_filter to fetch the current tenant and pass it to `acts_as_tenant` by using `set_current_tenant(current_tenant)` in the before_filter.
70
+ 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
71
 
72
72
 
73
73
  ### Setting the current tenant for a block ###
@@ -213,7 +213,6 @@ If you want to contribute, fork the project, code your improvements and make a p
213
213
  Author & Credits
214
214
  ----------------
215
215
  acts_as_tenant is written by Erwin Matthijssen.
216
- Erwin is currently busy developing [Roll Call](http://www.rollcallapp.com/ "Roll Call App").
217
216
 
218
217
  This gem was inspired by Ryan Sonnek's [Multitenant](https://github.com/wireframe/multitenant) gem and its use of default_scope.
219
218
 
@@ -0,0 +1 @@
1
+ theme: jekyll-theme-tactile
@@ -19,12 +19,12 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  s.add_runtime_dependency('request_store', '>= 1.0.5')
22
- s.add_dependency('rails','>= 3.1')
22
+ s.add_dependency('rails','>= 4.0')
23
23
  #s.add_dependency('request_store', '>= 1.0.5')
24
24
 
25
25
  s.add_development_dependency('rspec', '>=3.0')
26
26
  s.add_development_dependency('rspec-rails')
27
- s.add_development_dependency('database_cleaner', '~> 1.3.0')
27
+ s.add_development_dependency('database_cleaner', '~> 1.5.3')
28
28
  s.add_development_dependency('sqlite3')
29
29
  #s.add_development_dependency('mongoid', '~> 4.0')
30
30
 
@@ -0,0 +1,67 @@
1
+ <h2> Adding multi-tenancy to your Rails app: acts_as_tenant </h2>
2
+ Roll Call is implemented as a multi-tenant application: each user gets their own instance of the app, content is strictly scoped to a user&#8217;s instance. In Rails, this can be achieved in various ways. Guy Naor did a great job of diving into the pros and cons of each option in his <a href="http://confreaks.net/videos/111-aac2009-writing-multi-tenant-applications-in-rails">2009 Acts As Conference talk</a>. If you are doing multi-tenancy in Rails, you should watch his video.</p>
3
+ <p>With a multi-db or multi-schema approach, you only deal with the multi-tenancy-aspect in a few specific spots in your app (Jerod Santo recently wrote an excellent post on implementing a <a href="http://blog.jerodsanto.net/2011/07/building-multi-tenant-rails-apps-with-postgresql-schemas/">multi-schema strategy</a>). Compared to the previous two strategies, a <strong>shared database</strong> strategy has the downside that the &#8216;multi-tenancy&#8217;-logic is something you need to actively be aware of and manage in almost every part of your app.</p>
4
+ <h4>Using a Shared Database strategy is alot of work!</h4>
5
+ <p>For various other reasons we opted for a <strong>shared database</strong> strategy. However, for us the prospect of dealing with the multi-tenancy-logic throughout our app, was not appealing. Worse, we run the risk of accidently exposing content of one tenant to another one, if we mismanage this logic. While researching this topic I noticed there are no real ready made solutions available that get you on your way, <a href="http://github.com/wireframe/multitenant">Ryan Sonnek</a> wrote his &#8216;multitenant&#8217; gem and <a href="http://github.com/mconnell/multi_tenant">Mark Connel</a> did the same. Neither of these solution seemed &#8220;finished&#8221; to us. So, we wrote our own implementation.</p>
6
+ <h4>First, how does multi-tenancy with a shared database strategy work</h4>
7
+ <p>A shared database strategy manages the multi-tenancy-logic through Rails associations. A tenant is represented by an object, for example an <code>Account</code>. All other objects are associated with a tenant: <code>belongs_to :account</code>. Each request starts with finding the <code>@current_account</code>. After that, each find is scoped through the tenant object: <code>current_account.projects.all</code>. This has to be remembered everywhere: in model method declarations and in controller actions. Otherwise, you&#8217;re exposing content of other tenants.</p>
8
+ <p>In addition, you have to actively babysit other parts of your app: <code>validates_uniqueness_of</code> requires you to scope it to the current tenant. You also have to protect agaist all sorts of form-injections that could allow one tenant to gain access or temper with the content of another tenant (see <a href="http://www.slideshare.net/tardate/multitenancy-with-rails">Paul Gallaghers</a> presentation for more on these dangers).</p>
9
+ <h4>Enter acts_as_tenant</h4>
10
+ <p>I wanted to implement all the concerns above in an easy to manage, out of the way fashion. We should be able to add a single declaration to our model and that should implement:</p>
11
+ <ol>
12
+ <li>scoping all searches to the current <code>Account</code></li>
13
+ <li>scoping the uniqueness validator to the current <code>Account</code></li>
14
+ <li>protecting against various nastiness trying to circumvent the scoping.</li>
15
+ </ol>
16
+ <p>The result is <code>acts_as_tenant</code> (<a href="https://github.com/ErwinM/acts_as_tenant">github</a>), a rails gem that will add multi tenancy using a shared database to your rails app in an out-of-your way fashion.</p>
17
+ <p>In the <span class="caps">README</span>, you will find more information on using <code>acts_as_tenant</code> in your projects, so we&#8217;ll give you a high-level overview here. Let&#8217;s suppose that you have an app to which you want to add multi tenancy, tenants are represented by the <code>Account</code> model and <code>Project</code> is one of the models that should be scoped by tenant:</p>
18
+
19
+ ```ruby
20
+ class Addaccounttoproject < ActiveRecord::Migration
21
+ def change
22
+ add_column :projects, :account_id, :integer
23
+ end
24
+ end
25
+
26
+ class Project < ActiveRecord::Base
27
+ acts_as_tenant(:account)
28
+ validates_uniqueness_to_tenant :name
29
+ end
30
+ ```
31
+ What does adding these two methods accomplish:
32
+ <ol>
33
+ <li>it ensures every search on the project model will be scoped to the current tenant,</li>
34
+ <li>it adds validation for every association confirming the associated object does indeed belong to the current tenant,</li>
35
+ <li>it validates the uniqueness of `:name` to the current tenant,</li>
36
+ <li>it implements a bunch of safeguards preventing all kinds of nastiness from exposing other tenants data (mainly form-injection attacks).</li>
37
+ </ol>
38
+ <p>Ofcourse, all the above assumes `acts_as_tenant` actually knows who the current tenant is. Two strategies are implemented to help with this.</p>
39
+ <p><strong>Using the subdomain to workout the current tenant</strong></p>
40
+
41
+ ```ruby
42
+ class ApplicationController < ActionController::Base
43
+ set_current_tenant_by_subdomain(:account, :subdomain)
44
+ end
45
+ ```
46
+ <p>Adding the above method to your `application_controller` tells `acts_as_tenant`:</p>
47
+ <ol>
48
+ <li>the current tenant should be found based on the subdomain (e.g. account1.myappdomain.com),</li>
49
+ <li>tenants are represented by the `Account`-model and</li>
50
+ <li>the `Account` model has a column named `subdomain` that should be used the lookup the current account, using the current subdomain.</li>
51
+ </ol>
52
+ <p><strong>Passing the current account to acts_as_tenant yourself</strong></p>
53
+
54
+ ```ruby
55
+ class ApplicationController < ActionController::Base
56
+ current_account = Account.method_to_find_the_current_account
57
+ set_current_tenant_to(current_account)
58
+ end
59
+ ```
60
+ <p>`Acts_as_tenant` also adds a handy helper to your controllers `current_tenant`, containing the current tenant object.</p>
61
+ <h4>Great! Anything else I should know? A few caveats:</h4>
62
+ <ul>
63
+ <li>scoping of models *only* works if `acts_as_tenant` has a current_tenant available. If you do not set one by one of the methods described above, *no scope* will be applied!</li>
64
+ <li>for validating uniqueness within a tenant scope you must use the `validates_uniqueness_to_tenant`method. This method takes all the options the regular `validates_uniqueness_of` method takes.</li>
65
+ <li>it is probably best to add the `acts_as_tenant` declaration after any other `default_scope` declarations you add to a model (I am not exactly sure how rails 3 handles the chaining. If someone can enlighten me, thanks!).</li>
66
+ </ul>
67
+ <p>We have been testing <a href="https://github.com/ErwinM/acts_as_tenant">acts_as_tenant</a> within Roll Call during recent weeks and it seems to be behaving well. Having said that, we welcome any feedback. This is my first real attempt at a plugin and the possibility of various improvements is almost a given.</p>
@@ -18,6 +18,10 @@ if defined?(ActionController::Base)
18
18
  ActionController::Base.extend ActsAsTenant::ControllerExtensions
19
19
  end
20
20
 
21
+ if defined?(ActionController::API)
22
+ ActionController::API.extend ActsAsTenant::ControllerExtensions
23
+ end
24
+
21
25
  module ActsAsTenant
22
26
  end
23
27
 
@@ -13,8 +13,10 @@ module ActsAsTenant
13
13
  self.tenant_column = column.to_sym
14
14
 
15
15
  self.class_eval do
16
- before_filter :find_tenant_by_subdomain
17
- helper_method :current_tenant
16
+
17
+ before_action :find_tenant_by_subdomain
18
+ helper_method :current_tenant if respond_to?(:helper_method)
19
+
18
20
 
19
21
  private
20
22
  def find_tenant_by_subdomain
@@ -42,8 +44,10 @@ module ActsAsTenant
42
44
  self.tenant_second_column = second_column.to_sym
43
45
 
44
46
  self.class_eval do
45
- before_filter :find_tenant_by_subdomain_or_domain
46
- helper_method :current_tenant
47
+
48
+ before_action :find_tenant_by_subdomain_or_domain
49
+ helper_method :current_tenant if respond_to?(:helper_method)
50
+
47
51
 
48
52
  private
49
53
  def find_tenant_by_subdomain_or_domain
@@ -62,10 +66,10 @@ module ActsAsTenant
62
66
 
63
67
 
64
68
  # This method sets up a method that allows manual setting of the current_tenant. This method should
65
- # be used in a before_filter. In addition, a helper is setup that returns the current_tenant
69
+ # be used in a before_action. In addition, a helper is setup that returns the current_tenant
66
70
  def set_current_tenant_through_filter
67
71
  self.class_eval do
68
- helper_method :current_tenant
72
+ helper_method :current_tenant if respond_to?(:helper_method)
69
73
 
70
74
  private
71
75
  def set_current_tenant(current_tenant_object)
@@ -1,3 +1,3 @@
1
1
  module ActsAsTenant
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -24,7 +24,7 @@ describe ActsAsTenant do
24
24
  @project = @account.projects.create!(:name => 'bar')
25
25
  end
26
26
 
27
- it { expect {@project.account_id = @account.id + 1}.to raise_error }
27
+ it { expect {@project.account_id = @account.id + 1}.to raise_error(ActsAsTenant::Errors::TenantIsImmutable) }
28
28
  end
29
29
 
30
30
  describe 'setting tenant_id to the same value should not error' do
@@ -8,7 +8,7 @@ end
8
8
  class ApplicationController2 < ActionController::Base
9
9
  include Rails.application.routes.url_helpers
10
10
  set_current_tenant_through_filter
11
- before_filter :your_method_that_finds_the_current_tenant
11
+ before_action :your_method_that_finds_the_current_tenant
12
12
 
13
13
  def your_method_that_finds_the_current_tenant
14
14
  current_account = Account.new
@@ -22,7 +22,7 @@ end
22
22
  describe ApplicationController2, :type => :controller do
23
23
  controller do
24
24
  def index
25
- render :text => "custom called"
25
+ render :plain => "custom called"
26
26
  end
27
27
  end
28
28
 
@@ -30,4 +30,4 @@ describe ApplicationController2, :type => :controller do
30
30
  get :index
31
31
  expect(ActsAsTenant.current_tenant.name).to eq 'account1'
32
32
  end
33
- end
33
+ end
@@ -12,7 +12,7 @@ end
12
12
  describe ApplicationController, :type => :controller do
13
13
  controller do
14
14
  def index
15
- render :text => "custom called"
15
+ render :plain => "custom called"
16
16
  end
17
17
  end
18
18
 
@@ -29,4 +29,4 @@ describe ApplicationController, :type => :controller do
29
29
  get :index
30
30
  expect(ActsAsTenant.current_tenant).to eq 'account1'
31
31
  end
32
- end
32
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_tenant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erwin Matthijssen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-13 00:00:00.000000000 Z
11
+ date: 2018-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: request_store
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '3.1'
33
+ version: '4.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '3.1'
40
+ version: '4.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 1.3.0
75
+ version: 1.5.3
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 1.3.0
82
+ version: 1.5.3
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: sqlite3
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -123,7 +123,9 @@ files:
123
123
  - MIT-LICENSE
124
124
  - README.md
125
125
  - Rakefile
126
+ - _config.yml
126
127
  - acts_as_tenant.gemspec
128
+ - docs/blog_post.md
127
129
  - lib/acts_as_tenant.rb
128
130
  - lib/acts_as_tenant/configuration.rb
129
131
  - lib/acts_as_tenant/controller_extensions.rb
@@ -161,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
163
  version: '0'
162
164
  requirements: []
163
165
  rubyforge_project: acts_as_tenant
164
- rubygems_version: 2.4.5.1
166
+ rubygems_version: 2.6.11
165
167
  signing_key:
166
168
  specification_version: 4
167
169
  summary: Add multi-tenancy to Rails applications using a shared db strategy