apartment 0.13.0.1 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm 1.9.2@apartment
1
+ rvm --create ruby-1.9.2-p180@apartment
data/HISTORY.md CHANGED
@@ -1,20 +1,19 @@
1
- # 0.13.0.1
2
- * Feb 9, 2012
3
-
4
- - Versioning has become a bit of a mess. Will maintain this line for Rails 3.0.x
5
- - Removing Rails dependency, now just depends on ActiveRecord :)
6
- - `drop` was somehow missed from the methods proxied through to the adapter, added that in.
1
+ # 0.13.1
2
+ * Nov 8, 2011
3
+
4
+ - Reset prepared statement cache for rails 3.1.1 before switching dbs when using postgresql schemas
5
+ - Only necessary until the next release which will be more schema aware
7
6
 
8
7
  # 0.13.0
9
8
  * Oct 25, 2011
10
-
9
+
11
10
  - `process` will now rescue with reset if the previous schema/db is no longer available
12
11
  - `create` now takes an optional block which allows you to process within the newly created db
13
12
  - Fixed Rails version >= 3.0.10 and < 3.1 because there have been significant testing problems with 3.1, next version will hopefully fix this
14
-
13
+
15
14
  # 0.12.0
16
15
  * Oct 4, 2011
17
-
16
+
18
17
  - Added a `drop` method for removing databases/schemas
19
18
  - Refactored abstract adapter to further remove duplication in concrete implementations
20
19
  - Excluded models now take string references so they are properly reloaded in development
@@ -22,7 +21,7 @@
22
21
 
23
22
  # 0.11.1
24
23
  * Sep 22, 2011
25
-
24
+
26
25
  - Better use of Railties for initializing apartment
27
26
  - The following changes were necessary as I haven't figured out how to properly hook into Rails reloading
28
27
  - Added reloader middleware in development to init Apartment on each request
@@ -30,88 +29,88 @@
30
29
 
31
30
  # 0.11.0
32
31
  * Sep 20, 2011
33
-
32
+
34
33
  - Excluded models no longer use a different connection when using postgresql schemas. Instead their table_name is prefixed with `public.`
35
34
 
36
35
  # 0.10.3
37
36
  * Sep 20, 2011
38
-
37
+
39
38
  - Fix improper raising of exceptions on create and reset
40
39
 
41
40
  # 0.10.2
42
41
  * Sep 15, 2011
43
-
42
+
44
43
  - Remove all the annoying logging for loading db schema and seeding on create
45
44
 
46
45
  # 0.10.1
47
46
  * Aug 11, 2011
48
-
47
+
49
48
  - Fixed bug in DJ where new objects (that hadn't been pulled from the db) didn't have the proper database assigned
50
49
 
51
50
  # 0.10.0
52
51
  * July 29, 2011
53
-
52
+
54
53
  - Added better support for Delayed Job
55
54
  - New config option that enables Delayed Job wrappers
56
55
  - Note that DJ support uses a work-around in order to get queues stored in the public schema, not sure why it doesn't work out of the box, will look into it, until then, see documentation on queue'ng jobs
57
-
56
+
58
57
  # 0.9.2
59
58
  * July 4, 2011
60
-
59
+
61
60
  - Migrations now run associated rails migration fully, fixes schema.rb not being reloaded after migrations
62
61
 
63
62
  # 0.9.1
64
63
  * June 24, 2011
65
-
64
+
66
65
  - Hooks now take the payload object as an argument to fetch the proper db for DJ hooks
67
66
 
68
67
  # 0.9.0
69
68
  * June 23, 2011
70
-
69
+
71
70
  - Added module to provide delayed job hooks
72
71
 
73
72
  # 0.8.0
74
73
  * June 23, 2011
75
-
74
+
76
75
  - Added #current_database which will return the current database (or schema) name
77
76
 
78
77
  # 0.7.0
79
78
  * June 22, 2011
80
-
79
+
81
80
  - Added apartment:seed rake task for seeding all dbs
82
81
 
83
82
  # 0.6.0
84
83
  * June 21, 2011
85
-
84
+
86
85
  - Added #process to connect to new db, perform operations, then ensure a reset
87
86
 
88
87
  # 0.5.1
89
88
  * June 21, 2011
90
-
89
+
91
90
  - Fixed db migrate up/down/rollback
92
91
  - added db:redo
93
92
 
94
93
  # 0.5.0
95
94
  * June 20, 2011
96
-
95
+
97
96
  - Added the concept of an "Elevator", a rack based strategy for db switching
98
97
  - Added the Subdomain Elevator middleware to enabled db switching based on subdomain
99
98
 
100
99
  # 0.4.0
101
100
  * June 14, 2011
102
-
101
+
103
102
  - Added `configure` method on Apartment instead of using yml file, allows for dynamic setting of db names to migrate for rake task
104
103
  - Added `seed_after_create` config option to import seed data to new db on create
105
-
104
+
106
105
  # 0.3.0
107
106
  * June 10, 2011
108
-
107
+
109
108
  - Added full support for database migration
110
109
  - Added in method to establish new connection for excluded models on startup rather than on each switch
111
-
110
+
112
111
  # 0.2.0
113
112
  * June 6, 2011 *
114
-
113
+
115
114
  - Refactor to use more rails/active_support functionality
116
115
  - Refactor config to lazily load apartment.yml if exists
117
116
  - Remove OStruct and just use hashes for fetching methods
@@ -7,28 +7,25 @@ Gem::Specification.new do |s|
7
7
  s.version = Apartment::VERSION
8
8
 
9
9
  s.authors = ["Ryan Brunner", "Brad Robertson"]
10
- s.summary = %q{A Ruby gem for managing database multitenancy in Rack applications using ActiveRecord}
11
- s.description = %q{Apartment allows applications using ActiveRecord to deal with database multitenancy}
10
+ s.summary = %q{A Ruby gem for managing database multitenancy in Rails applications}
11
+ s.description = %q{Apartment allows Rails applications to deal with database multitenancy}
12
12
  s.email = %w{ryan@ryanbrunner.com bradleyrobertson@gmail.com}
13
13
  s.files = `git ls-files`.split("\n")
14
14
  s.test_files = `git ls-files -- {spec}/*`.split("\n")
15
-
15
+
16
16
  s.homepage = %q{http://github.com/bradrobertson/apartment}
17
17
  s.licenses = ["MIT"]
18
18
  s.require_paths = ["lib"]
19
19
  s.rubygems_version = %q{1.3.7}
20
-
21
- s.add_dependency 'activerecord', '~> 3.0.10' # must be >= 3.0.10 due to poor schema support pre 3.0.10
22
- s.add_dependency 'rack', '~> 1.2.5'
23
-
24
- s.add_development_dependency 'rake', '~> 0.8.7'
25
- s.add_development_dependency 'rails', '~> 3.0.10'
20
+
21
+ s.add_dependency 'rails', '~> 3.1.1' # must be >= 3.0.10 due to poor schema support pre 3.0.10, but < 3.1 because it hasn't been fully tested yet
22
+ s.add_development_dependency 'rake', '~> 0.8.7'
26
23
  s.add_development_dependency 'sqlite3'
27
- s.add_development_dependency 'rspec', '~> 2.6.0'
28
- s.add_development_dependency 'rspec-rails', '~> 2.6.1'
29
- s.add_development_dependency 'capybara', '1.0.0'
30
- s.add_development_dependency 'pg', '~> 0.11.0'
31
- s.add_development_dependency 'mysql2', '0.2.7'
24
+ s.add_development_dependency 'rspec', '~> 2.6.0'
25
+ s.add_development_dependency 'rspec-rails', '~> 2.6.1'
26
+ s.add_development_dependency 'capybara', '1.0.0'
27
+ s.add_development_dependency 'pg', '~> 0.11.0'
28
+ s.add_development_dependency 'mysql2', '0.2.7'
32
29
  s.add_development_dependency "silent-postgres", "~> 0.1.1"
33
- s.add_development_dependency 'delayed_job', '~> 2.1.4'
30
+ s.add_development_dependency 'delayed_job', '~> 2.1.4'
34
31
  end
@@ -1,19 +1,16 @@
1
1
  require 'apartment/railtie' if defined?(Rails)
2
2
 
3
3
  module Apartment
4
-
4
+
5
5
  class << self
6
- ACCESSOR_METHODS = [:use_postgres_schemas, :seed_after_create, :prepend_environment]
7
- WRITER_METHODS = [:database_names, :excluded_models, :load_schema]
8
-
9
- attr_accessor(*ACCESSOR_METHODS)
10
- attr_writer(*WRITER_METHODS)
11
-
6
+ attr_accessor :use_postgres_schemas, :seed_after_create, :prepend_environment
7
+ attr_writer :database_names, :excluded_models
8
+
12
9
  # configure apartment with available options
13
10
  def configure
14
11
  yield self if block_given?
15
12
  end
16
-
13
+
17
14
  # Be careful not to use `return` here so both Proc and lambda can be used without breaking
18
15
  def database_names
19
16
  if @database_names.respond_to?(:call)
@@ -22,65 +19,55 @@ module Apartment
22
19
  @database_names
23
20
  end
24
21
  end
25
-
22
+
26
23
  # Default to none
27
24
  def excluded_models
28
25
  @excluded_models || []
29
26
  end
30
-
31
- # Defaults to true if not set
32
- def load_schema
33
- @load_schema != false
34
- end
35
-
36
- # Reset all the config for Apartment
37
- def reset
38
- (ACCESSOR_METHODS + WRITER_METHODS).each{|method| instance_variable_set(:"@#{method}", nil) }
39
- end
40
-
27
+
41
28
  end
42
-
29
+
43
30
  autoload :Database, 'apartment/database'
44
31
  autoload :Migrator, 'apartment/migrator'
45
32
  autoload :Reloader, 'apartment/reloader'
46
-
33
+
47
34
  module Adapters
48
35
  autoload :AbstractAdapter, 'apartment/adapters/abstract_adapter'
49
36
  # Specific adapters will be loaded dynamically based on adapter in config
50
37
  end
51
-
38
+
52
39
  module Elevators
53
40
  autoload :Subdomain, 'apartment/elevators/subdomain'
54
41
  end
55
-
42
+
56
43
  module Delayed
57
-
44
+
58
45
  autoload :Requirements, 'apartment/delayed_job/requirements'
59
-
46
+
60
47
  module Job
61
48
  autoload :Hooks, 'apartment/delayed_job/hooks'
62
49
  end
63
50
  end
64
-
51
+
65
52
  # Exceptions
66
53
  class ApartmentError < StandardError; end
67
-
54
+
68
55
  # Raised when apartment cannot find the adapter specified in <tt>config/database.yml</tt>
69
56
  class AdapterNotFound < ApartmentError; end
70
-
57
+
71
58
  # Raised when database cannot find the specified database
72
59
  class DatabaseNotFound < ApartmentError; end
73
-
60
+
74
61
  # Raised when trying to create a database that already exists
75
62
  class DatabaseExists < ApartmentError; end
76
-
63
+
77
64
  # Raised when database cannot find the specified schema
78
65
  class SchemaNotFound < ApartmentError; end
79
-
66
+
80
67
  # Raised when trying to create a schema that already exists
81
68
  class SchemaExists < ApartmentError; end
82
-
69
+
83
70
  # Raised when an ActiveRecord object does not have the required database field on it
84
71
  class DJSerializationError < ApartmentError; end
85
-
72
+
86
73
  end
@@ -1,81 +1,81 @@
1
1
  require 'active_record'
2
2
 
3
3
  module Apartment
4
-
4
+
5
5
  module Adapters
6
-
6
+
7
7
  class AbstractAdapter
8
-
8
+
9
9
  # @constructor
10
10
  # @param {Hash} config Database config
11
11
  # @param {Hash} defaults Some default options
12
- #
12
+ #
13
13
  def initialize(config, defaults = {})
14
14
  @config = config
15
15
  @defaults = defaults
16
16
  end
17
-
17
+
18
18
  # Create a new database, import schema, seed if appropriate
19
- #
19
+ #
20
20
  # @param {String} database Database name
21
- #
22
- def create(database)
23
- create_database(database)
21
+ #
22
+ def create(database)
23
+ create_database(database)
24
24
 
25
- process(database) do
26
- import_database_schema if Apartment.load_schema
25
+ process(database) do
26
+ import_database_schema
27
27
 
28
28
  # Seed data if appropriate
29
29
  seed_data if Apartment.seed_after_create
30
-
30
+
31
31
  yield if block_given?
32
- end
33
- end
34
-
32
+ end
33
+ end
34
+
35
35
  # Get the current database name
36
- #
36
+ #
37
37
  # @return {String} current database name
38
- #
38
+ #
39
39
  def current_database
40
40
  ActiveRecord::Base.connection.current_database
41
41
  end
42
-
42
+
43
43
  # Drop the database
44
- #
44
+ #
45
45
  # @param {String} database Database name
46
- #
46
+ #
47
47
  def drop(database)
48
48
  # ActiveRecord::Base.connection.drop_database note that drop_database will not throw an exception, so manually execute
49
49
  ActiveRecord::Base.connection.execute("DROP DATABASE #{environmentify(database)}" )
50
-
51
- rescue ActiveRecord::StatementInvalid
50
+
51
+ rescue ActiveRecord::StatementInvalid => e
52
52
  raise DatabaseNotFound, "The database #{environmentify(database)} cannot be found"
53
53
  end
54
-
54
+
55
55
  # Prepend the environment if configured and the environment isn't already there
56
- #
56
+ #
57
57
  # @param {String} database Database name
58
58
  # @return {String} database name with Rails environment *optionally* prepended
59
- #
59
+ #
60
60
  def environmentify(database)
61
61
  Apartment.prepend_environment && !database.include?(Rails.env) ? "#{Rails.env}_#{database}" : database
62
- end
63
-
62
+ end
63
+
64
64
  # Connect to db, do your biz, switch back to previous db
65
- #
65
+ #
66
66
  # @param {String?} database Database or schema to connect to
67
- #
67
+ #
68
68
  def process(database = nil)
69
69
  current_db = current_database
70
70
  switch(database)
71
71
  yield if block_given?
72
-
73
- ensure
72
+
73
+ ensure
74
74
  switch(current_db) rescue reset
75
- end
76
-
75
+ end
76
+
77
77
  # Establish a new connection for each specific excluded model
78
- #
78
+ #
79
79
  def process_excluded_models
80
80
  # All other models will shared a connection (at ActiveRecord::Base) and we can modify at will
81
81
  Apartment.excluded_models.each do |excluded_model|
@@ -85,77 +85,77 @@ module Apartment
85
85
  warn "[Deprecation Warning] Passing class references to excluded models is now deprecated, please use a string instead"
86
86
  excluded_model = excluded_model.name
87
87
  end
88
-
88
+
89
89
  excluded_model.constantize.establish_connection @config
90
90
  end
91
91
  end
92
-
92
+
93
93
  # Reset the database connection to the default
94
- #
94
+ #
95
95
  def reset
96
96
  ActiveRecord::Base.establish_connection @config
97
97
  end
98
-
98
+
99
99
  # Switch to new connection (or schema if appopriate)
100
- #
100
+ #
101
101
  # @param {String} database Database name
102
- #
102
+ #
103
103
  def switch(database = nil)
104
104
  # Just connect to default db and return
105
105
  return reset if database.nil?
106
106
 
107
107
  connect_to_new(database)
108
- end
108
+ end
109
109
 
110
110
  # Load the rails seed file into the db
111
- #
112
- def seed_data
111
+ #
112
+ def seed_data
113
113
  silence_stream(STDOUT){ load_or_abort("#{Rails.root}/db/seeds.rb") } # Don't log the output of seeding the db
114
114
  end
115
115
  alias_method :seed, :seed_data
116
-
116
+
117
117
  protected
118
-
118
+
119
119
  # Create the database
120
- #
120
+ #
121
121
  # @param {String} database Database name
122
- #
122
+ #
123
123
  def create_database(database)
124
124
  ActiveRecord::Base.connection.create_database( environmentify(database) )
125
125
 
126
- rescue ActiveRecord::StatementInvalid
126
+ rescue ActiveRecord::StatementInvalid => e
127
127
  raise DatabaseExists, "The database #{environmentify(database)} already exists."
128
128
  end
129
-
129
+
130
130
  # Connect to new database
131
- #
131
+ #
132
132
  # @param {String} database Database name
133
- #
133
+ #
134
134
  def connect_to_new(database)
135
135
  ActiveRecord::Base.establish_connection multi_tenantify(database)
136
136
  ActiveRecord::Base.connection.active? # call active? to manually check if this connection is valid
137
137
 
138
- rescue ActiveRecord::StatementInvalid
138
+ rescue ActiveRecord::StatementInvalid => e
139
139
  raise DatabaseNotFound, "The database #{environmentify(database)} cannot be found."
140
- end
141
-
140
+ end
141
+
142
142
  # Import the database schema
143
- #
143
+ #
144
144
  def import_database_schema
145
145
  ActiveRecord::Schema.verbose = false # do not log schema load output.
146
146
  load_or_abort("#{Rails.root}/db/schema.rb")
147
147
  end
148
-
148
+
149
149
  # Return a new config that is multi-tenanted
150
- #
150
+ #
151
151
  def multi_tenantify(database)
152
152
  @config.clone.tap do |config|
153
153
  config[:database] = environmentify(database)
154
154
  end
155
- end
156
-
155
+ end
156
+
157
157
  # Load a file or abort if it doesn't exists
158
- #
158
+ #
159
159
  def load_or_abort(file)
160
160
  if File.exists?(file)
161
161
  load(file)
@@ -163,14 +163,14 @@ module Apartment
163
163
  abort %{#{file} doesn't exist yet}
164
164
  end
165
165
  end
166
-
166
+
167
167
  # Remove all non-alphanumeric characters
168
- #
169
- def sanitize(database)
168
+ #
169
+ def sanitize(database)
170
170
  warn "[Deprecation Warning] Sanitize is no longer used, client should ensure proper database names"
171
171
  database.gsub(/[\W]/,'')
172
172
  end
173
-
173
+
174
174
  end
175
175
  end
176
176
  end