apartment 0.1.3
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.
- data/.bundle/config +2 -0
- data/.project +11 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +22 -0
- data/README.markdown +95 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/apartment.gemspec +68 -0
- data/lib/apartment.rb +11 -0
- data/lib/apartment/associations/multi_tenant_association.rb +0 -0
- data/lib/apartment/config.rb +10 -0
- data/lib/apartment/config/default_config.yml +17 -0
- data/lib/apartment/database.rb +80 -0
- data/lib/apartment/railtie.rb +10 -0
- data/lib/tasks/multi_tenant_migrate.rake +14 -0
- data/pkg/apartment-0.1.3.gem +0 -0
- metadata +153 -0
data/.bundle/config
ADDED
data/.project
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
|
5
|
+
gem "activesupport", ">= 2.3.5"
|
6
|
+
|
7
|
+
|
8
|
+
# Add dependencies to develop your gem here.
|
9
|
+
# Include everything needed to run rake, tests, features, etc.
|
10
|
+
group :development do
|
11
|
+
gem "shoulda", ">= 0"
|
12
|
+
gem "bundler", "~> 1.0.0"
|
13
|
+
gem "jeweler", "~> 1.5.1"
|
14
|
+
gem "rcov", ">= 0"
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.0.3)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.5.1)
|
7
|
+
bundler (~> 1.0.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rake (0.8.7)
|
11
|
+
rcov (0.9.9)
|
12
|
+
shoulda (2.11.3)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
activesupport (>= 2.3.5)
|
19
|
+
bundler (~> 1.0.0)
|
20
|
+
jeweler (~> 1.5.1)
|
21
|
+
rcov
|
22
|
+
shoulda
|
data/README.markdown
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# Apartment
|
2
|
+
*Multitenancy for Rails 3*
|
3
|
+
|
4
|
+
Apartment provides tools to help you deal with multiple databases in your Rails
|
5
|
+
environment. If you need to have certain data sequestered based on account or company,
|
6
|
+
but still allow some data to exist in a common database, Apartment can help.
|
7
|
+
|
8
|
+
## Caveats
|
9
|
+
|
10
|
+
Apartment was built to deal with a very particular use-case - the need to spin up
|
11
|
+
multiple databases within the same application instance on-demand while Rails is running.
|
12
|
+
If your setup can accomodate creating new databases on deploy (by adding a new database to your
|
13
|
+
database.yml), or doesn't need 100% database isolation, other solutions might be far simpler
|
14
|
+
for your use case.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
### Rails 3
|
19
|
+
|
20
|
+
Add the following to your Gemfile:
|
21
|
+
|
22
|
+
gem 'apartment'
|
23
|
+
|
24
|
+
That's all you need to set up the Apartment libraries. If you want to switch databases
|
25
|
+
on a per-user basis, look under "Usage - Switching databases per request", below.
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Creating new Databases
|
30
|
+
|
31
|
+
Before you can switch to a new apartment database, you will need to create it. Whenever
|
32
|
+
you need to create a new database, you can run the following command:
|
33
|
+
|
34
|
+
Apartment::Database.create('database_name')
|
35
|
+
|
36
|
+
Apartment will create a new database in the following format: "environment_database_name".
|
37
|
+
In the case of a sqlite database, this will be created in your 'db/migrate' foler. With
|
38
|
+
other databases, the database will be created as a new DB within the system.
|
39
|
+
|
40
|
+
When you create a new database, all migrations will be run against that database, so it will be
|
41
|
+
up to date when create returns.
|
42
|
+
|
43
|
+
#### Notes on PostgreSQL
|
44
|
+
|
45
|
+
PostgreSQL works slightly differently than other databases when creating a new DB. If you
|
46
|
+
are using PostgreSQL, Apartment will set up a new **schema** and migrate into there. This
|
47
|
+
provides better performance, and allows Apartment to work on systems like Heroku, which
|
48
|
+
would not allow a full new database to be created.
|
49
|
+
|
50
|
+
### Switching Databases
|
51
|
+
|
52
|
+
To switch databases using Apartment, use the following command:
|
53
|
+
|
54
|
+
Apartment::Database.switch('database_name')
|
55
|
+
|
56
|
+
When switch is called, all requests coming to ActiveRecord will be routed to the database
|
57
|
+
you specify (with the exception of excluded models, see below). To return to the 'root'
|
58
|
+
database, call switch with no arguments.
|
59
|
+
|
60
|
+
### Switching Databases per request
|
61
|
+
|
62
|
+
You can have Apartment route to the appropriate database per request by adding a warden task
|
63
|
+
in application.rb. For instance, if you want to route to a particular database depending on
|
64
|
+
user, and you have a database attribute on your user model, you could do the following:
|
65
|
+
|
66
|
+
Warden::Manager.on_request do |proxy|
|
67
|
+
if session[:user_id]
|
68
|
+
u = User.find(session[:user_id])
|
69
|
+
Apartment::Database.switch(u.database)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
### Excluding models
|
74
|
+
|
75
|
+
If you have some models that should always access the 'root' database, you can specify this in
|
76
|
+
a configuration file. Apartment will look for a config file called 'apartment.yml' in the /config
|
77
|
+
directory of your Rails application. To exclude certain models, do the following:
|
78
|
+
|
79
|
+
excluded_models: [User, Company]
|
80
|
+
|
81
|
+
### Managing Migrations
|
82
|
+
|
83
|
+
Currently, you will need to migrate each database individually. I'll be working on code to
|
84
|
+
migrate all known databases soon. You can migrate any database up to the current version by
|
85
|
+
calling:
|
86
|
+
|
87
|
+
Apartment::Database.migrate('database_name')
|
88
|
+
|
89
|
+
## TODO
|
90
|
+
|
91
|
+
* Migration support
|
92
|
+
* Other rake task support
|
93
|
+
* Cross-database associations
|
94
|
+
|
95
|
+
## Contributing
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "apartment"
|
16
|
+
gem.homepage = "http://github.com/ryanbrunner/apartment"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{A Ruby gem for managing multitenancy in Rails applications}
|
19
|
+
gem.description = %Q{Apartment allows Rails applications to deal with
|
20
|
+
multitenancy.}
|
21
|
+
gem.email = "ryan@ryanbrunner.com"
|
22
|
+
gem.authors = ["Ryan Brunner"]
|
23
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
24
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
25
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
26
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
27
|
+
end
|
28
|
+
Jeweler::RubygemsDotOrgTasks.new
|
29
|
+
|
30
|
+
require 'rake/testtask'
|
31
|
+
Rake::TestTask.new(:test) do |test|
|
32
|
+
test.libs << 'lib' << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
|
37
|
+
require 'rcov/rcovtask'
|
38
|
+
Rcov::RcovTask.new do |test|
|
39
|
+
test.libs << 'test'
|
40
|
+
test.pattern = 'test/**/test_*.rb'
|
41
|
+
test.verbose = true
|
42
|
+
end
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "apartment #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.3
|
data/apartment.gemspec
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{apartment}
|
8
|
+
s.version = "0.1.3"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ryan Brunner"]
|
12
|
+
s.date = %q{2011-03-04}
|
13
|
+
s.description = %q{Apartment allows Rails applications to deal with
|
14
|
+
multitenancy.}
|
15
|
+
s.email = %q{ryan@ryanbrunner.com}
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".bundle/config",
|
21
|
+
".project",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"README.markdown",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"apartment.gemspec",
|
28
|
+
"lib/apartment.rb",
|
29
|
+
"lib/apartment/associations/multi_tenant_association.rb",
|
30
|
+
"lib/apartment/config.rb",
|
31
|
+
"lib/apartment/config/default_config.yml",
|
32
|
+
"lib/apartment/database.rb",
|
33
|
+
"lib/apartment/railtie.rb",
|
34
|
+
"lib/tasks/multi_tenant_migrate.rake",
|
35
|
+
"pkg/apartment-0.1.3.gem"
|
36
|
+
]
|
37
|
+
s.homepage = %q{http://github.com/ryanbrunner/apartment}
|
38
|
+
s.licenses = ["MIT"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubygems_version = %q{1.3.7}
|
41
|
+
s.summary = %q{A Ruby gem for managing multitenancy in Rails applications}
|
42
|
+
|
43
|
+
if s.respond_to? :specification_version then
|
44
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
45
|
+
s.specification_version = 3
|
46
|
+
|
47
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 3.0.5"])
|
49
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
50
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
51
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
52
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<activesupport>, [">= 3.0.5"])
|
55
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
56
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
58
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<activesupport>, [">= 3.0.5"])
|
62
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
63
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
65
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/lib/apartment.rb
ADDED
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Apartment configuration
|
2
|
+
|
3
|
+
# Excluded models
|
4
|
+
# Indicate which models should be excluded from multi-tenancy. If you have information
|
5
|
+
# that does not vary between databases, or information that should be considered global,
|
6
|
+
# specify it here. Any classes involved in determining which database to access MUST be
|
7
|
+
# specified here
|
8
|
+
|
9
|
+
excluded_models: [User]
|
10
|
+
|
11
|
+
# Postgres integration mode
|
12
|
+
# By default, apartment switches databases in Postgres by changing the schema search path
|
13
|
+
# of the current environment database. If preferred, this can be turned off and Postgres will
|
14
|
+
# look in different databases for multi-tenanted models.
|
15
|
+
|
16
|
+
use_postgres_schemas: true
|
17
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
module Apartment
|
3
|
+
class Database
|
4
|
+
def self.switch(database)
|
5
|
+
|
6
|
+
config = get_default_database
|
7
|
+
|
8
|
+
if database.nil?
|
9
|
+
ActiveRecord::Base.establish_connection(config)
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
switched_config = multi_tenantify(config, database)
|
14
|
+
|
15
|
+
puts switched_config.to_yaml
|
16
|
+
|
17
|
+
ActiveRecord::Base.establish_connection(switched_config)
|
18
|
+
|
19
|
+
puts Apartment::Config.excluded_models
|
20
|
+
|
21
|
+
Apartment::Config.excluded_models.each do |m|
|
22
|
+
klass = Kernel
|
23
|
+
m.split("::").each do |i|
|
24
|
+
klass = klass.const_get(i)
|
25
|
+
end
|
26
|
+
|
27
|
+
raise "Excluded class #{klass} could not be found." if klass.nil?
|
28
|
+
|
29
|
+
puts "Excluding class #{m}"
|
30
|
+
|
31
|
+
klass.establish_connection(config)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.create(database)
|
36
|
+
config = get_default_database
|
37
|
+
|
38
|
+
switched_config = multi_tenantify(config, database)
|
39
|
+
|
40
|
+
ActiveRecord::Base.establish_connection(switched_config)
|
41
|
+
|
42
|
+
if config["adapter"] == "postgresql"
|
43
|
+
ActiveRecord::Base.connection.execute('create table schema_migrations(version varchar(255))')
|
44
|
+
end
|
45
|
+
|
46
|
+
migrate(database)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.migrate(database)
|
50
|
+
|
51
|
+
config = get_default_database
|
52
|
+
switched_config = multi_tenantify(config, database)
|
53
|
+
|
54
|
+
ActiveRecord::Base.establish_connection(switched_config)
|
55
|
+
|
56
|
+
|
57
|
+
ActiveRecord::Migrator.migrate(File.join(Rails.root, 'db', 'migrate'))
|
58
|
+
|
59
|
+
ActiveRecord::Base.establish_connection(config)
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
def self.get_default_database
|
64
|
+
Rails.configuration.database_configuration[Rails.env]
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.multi_tenantify(configuration, database)
|
68
|
+
new_config = configuration.clone
|
69
|
+
|
70
|
+
if new_config['adapter'] == "postgresql"
|
71
|
+
new_config['schema_search_path'] = database
|
72
|
+
else
|
73
|
+
new_config['database'] = new_config['database'].gsub(Rails.env.to_s, "#{database}_#{Rails.env}")
|
74
|
+
end
|
75
|
+
|
76
|
+
new_config
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
namespace :apartment do
|
2
|
+
desc "Apply database changes to all multi-tenant databases"
|
3
|
+
task :migrate => :environment do |t, args|
|
4
|
+
|
5
|
+
puts "[Migrating to default environment]"
|
6
|
+
ActiveRecord::Migrator.migrate(File.join(Rails.root, 'db', 'migrate'))
|
7
|
+
|
8
|
+
Admin::Company.where("database is not null").select("distinct database").each do |u|
|
9
|
+
puts "[Migrating to #{u.database}]"
|
10
|
+
|
11
|
+
Apartment::Database.migrate u.database
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: apartment
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 3
|
9
|
+
version: 0.1.3
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ryan Brunner
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-04-18 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: activesupport
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 3
|
30
|
+
- 5
|
31
|
+
version: 2.3.5
|
32
|
+
type: :runtime
|
33
|
+
prerelease: false
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: shoulda
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
version: "0"
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: bundler
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 1
|
57
|
+
- 0
|
58
|
+
- 0
|
59
|
+
version: 1.0.0
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: jeweler
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 1
|
72
|
+
- 5
|
73
|
+
- 1
|
74
|
+
version: 1.5.1
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rcov
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *id005
|
91
|
+
description: |-
|
92
|
+
Apartment allows Rails applications to deal with
|
93
|
+
multitenancy.
|
94
|
+
email: ryan@ryanbrunner.com
|
95
|
+
executables: []
|
96
|
+
|
97
|
+
extensions: []
|
98
|
+
|
99
|
+
extra_rdoc_files:
|
100
|
+
- README.markdown
|
101
|
+
files:
|
102
|
+
- .bundle/config
|
103
|
+
- .project
|
104
|
+
- Gemfile
|
105
|
+
- Gemfile.lock
|
106
|
+
- README.markdown
|
107
|
+
- Rakefile
|
108
|
+
- VERSION
|
109
|
+
- apartment-0.1.3.gem
|
110
|
+
- apartment.gemspec
|
111
|
+
- lib/apartment.rb
|
112
|
+
- lib/apartment/associations/multi_tenant_association.rb
|
113
|
+
- lib/apartment/config.rb
|
114
|
+
- lib/apartment/config/default_config.yml
|
115
|
+
- lib/apartment/database.rb
|
116
|
+
- lib/apartment/railtie.rb
|
117
|
+
- lib/tasks/multi_tenant_migrate.rake
|
118
|
+
- pkg/apartment-0.1.3.gem
|
119
|
+
has_rdoc: true
|
120
|
+
homepage: http://github.com/ryanbrunner/apartment
|
121
|
+
licenses:
|
122
|
+
- MIT
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
|
126
|
+
require_paths:
|
127
|
+
- lib
|
128
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
hash: -190181027694817836
|
134
|
+
segments:
|
135
|
+
- 0
|
136
|
+
version: "0"
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
version: "0"
|
145
|
+
requirements: []
|
146
|
+
|
147
|
+
rubyforge_project:
|
148
|
+
rubygems_version: 1.3.7
|
149
|
+
signing_key:
|
150
|
+
specification_version: 3
|
151
|
+
summary: A Ruby gem for managing multitenancy in Rails applications
|
152
|
+
test_files: []
|
153
|
+
|