Permalink
Browse files

Support establishing connection on ActiveRecord::Model.

This is the 'top level' connection, inherited by any models that include
ActiveRecord::Model or inherit from ActiveRecord::Base.
  • Loading branch information...
1 parent 93c1f11 commit dae7b6545372cba40e08554b9a7b2f391eaa5c6e @jonleighton jonleighton committed Dec 28, 2011
Showing with 251 additions and 230 deletions.
  1. +1 −0 activerecord/lib/active_record.rb
  2. +1 −1 activerecord/lib/active_record/attribute_methods.rb
  3. +0 −1 activerecord/lib/active_record/base.rb
  4. +1 −1 activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
  5. +0 −184 activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
  6. +1 −1 activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
  7. +79 −0 activerecord/lib/active_record/connection_adapters/connection_specification.rb
  8. +1 −1 activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
  9. +1 −1 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
  10. +1 −1 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  11. +1 −1 activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
  12. +100 −0 activerecord/lib/active_record/connection_handling.rb
  13. +8 −7 activerecord/lib/active_record/core.rb
  14. +8 −12 activerecord/lib/active_record/inheritance.rb
  15. +16 −0 activerecord/lib/active_record/model.rb
  16. +1 −5 activerecord/lib/active_record/model_schema.rb
  17. +15 −4 activerecord/test/cases/base_test.rb
  18. +1 −1 activerecord/test/cases/connection_adapters/abstract_adapter_test.rb
  19. +1 −1 activerecord/test/cases/connection_specification/resolver_test.rb
  20. +4 −1 activerecord/test/cases/inclusion_test.rb
  21. +0 −1 activerecord/test/cases/inheritance_test.rb
  22. +3 −3 activerecord/test/cases/unconnected_test.rb
  23. +3 −0 activerecord/test/models/teapot.rb
  24. +1 −0 activerecord/test/schema/schema.rb
  25. +3 −3 activerecord/test/support/connection.rb
@@ -59,6 +59,7 @@ module ActiveRecord
autoload :Callbacks
autoload :Core
autoload :CounterCache
+ autoload :ConnectionHandling
autoload :DynamicMatchers
autoload :DynamicFinderMatch
autoload :DynamicScopeMatch
@@ -61,7 +61,7 @@ def instance_method_already_implemented?(method_name)
raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord"
end
- if active_record_super == Base
+ if [Base, Model].include?(active_record_super)
super
else
# If B < A and A defines its own attribute method, then we don't want to overwrite that.
@@ -331,5 +331,4 @@ class Base
end
end
-require 'active_record/connection_adapters/abstract/connection_specification'
ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Model::DeprecationProxy)
@@ -370,7 +370,7 @@ def remove_connection(klass)
def retrieve_connection_pool(klass)
pool = @class_to_pool[klass.name]
return pool if pool
- return nil if ActiveRecord::Base == klass
+ return nil if ActiveRecord::Model == klass
retrieve_connection_pool klass.active_record_super
end
end
@@ -1,184 +0,0 @@
-require 'active_support/core_ext/module/delegation'
-
-module ActiveRecord
- module Core
- class ConnectionSpecification #:nodoc:
- attr_reader :config, :adapter_method
- def initialize (config, adapter_method)
- @config, @adapter_method = config, adapter_method
- end
-
- ##
- # Builds a ConnectionSpecification from user input
- class Resolver # :nodoc:
- attr_reader :config, :klass, :configurations
-
- def initialize(config, configurations)
- @config = config
- @configurations = configurations
- end
-
- def spec
- case config
- when nil
- raise AdapterNotSpecified unless defined?(Rails.env)
- resolve_string_connection Rails.env
- when Symbol, String
- resolve_string_connection config.to_s
- when Hash
- resolve_hash_connection config
- end
- end
-
- private
- def resolve_string_connection(spec) # :nodoc:
- hash = configurations.fetch(spec) do |k|
- connection_url_to_hash(k)
- end
-
- raise(AdapterNotSpecified, "#{spec} database is not configured") unless hash
-
- resolve_hash_connection hash
- end
-
- def resolve_hash_connection(spec) # :nodoc:
- spec = spec.symbolize_keys
-
- raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
-
- begin
- require "active_record/connection_adapters/#{spec[:adapter]}_adapter"
- rescue LoadError => e
- raise LoadError, "Please install the #{spec[:adapter]} adapter: `gem install activerecord-#{spec[:adapter]}-adapter` (#{e.message})", e.backtrace
- end
-
- adapter_method = "#{spec[:adapter]}_connection"
-
- ConnectionSpecification.new(spec, adapter_method)
- end
-
- def connection_url_to_hash(url) # :nodoc:
- config = URI.parse url
- adapter = config.scheme
- adapter = "postgresql" if adapter == "postgres"
- spec = { :adapter => adapter,
- :username => config.user,
- :password => config.password,
- :port => config.port,
- :database => config.path.sub(%r{^/},""),
- :host => config.host }
- spec.reject!{ |_,value| !value }
- if config.query
- options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys
- spec.merge!(options)
- end
- spec
- end
- end
- end
-
- # Returns the connection currently associated with the class. This can
- # also be used to "borrow" the connection to do database work that isn't
- # easily done without going straight to SQL.
- def connection
- self.class.connection
- end
-
- module ClassMethods
- # Establishes the connection to the database. Accepts a hash as input where
- # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
- # example for regular databases (MySQL, Postgresql, etc):
- #
- # ActiveRecord::Base.establish_connection(
- # :adapter => "mysql",
- # :host => "localhost",
- # :username => "myuser",
- # :password => "mypass",
- # :database => "somedatabase"
- # )
- #
- # Example for SQLite database:
- #
- # ActiveRecord::Base.establish_connection(
- # :adapter => "sqlite",
- # :database => "path/to/dbfile"
- # )
- #
- # Also accepts keys as strings (for parsing from YAML for example):
- #
- # ActiveRecord::Base.establish_connection(
- # "adapter" => "sqlite",
- # "database" => "path/to/dbfile"
- # )
- #
- # Or a URL:
- #
- # ActiveRecord::Base.establish_connection(
- # "postgres://myuser:mypass@localhost/somedatabase"
- # )
- #
- # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
- # may be returned on an error.
- def establish_connection(spec = ENV["DATABASE_URL"])
- resolver = ConnectionSpecification::Resolver.new spec, configurations
- spec = resolver.spec
-
- unless respond_to?(spec.adapter_method)
- raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
- end
-
- remove_connection
- connection_handler.establish_connection name, spec
- end
-
- # Returns the connection currently associated with the class. This can
- # also be used to "borrow" the connection to do database work unrelated
- # to any of the specific Active Records.
- def connection
- retrieve_connection
- end
-
- def connection_id
- Thread.current['ActiveRecord::Base.connection_id']
- end
-
- def connection_id=(connection_id)
- Thread.current['ActiveRecord::Base.connection_id'] = connection_id
- end
-
- # Returns the configuration of the associated connection as a hash:
- #
- # ActiveRecord::Base.connection_config
- # # => {:pool=>5, :timeout=>5000, :database=>"db/development.sqlite3", :adapter=>"sqlite3"}
- #
- # Please use only for reading.
- def connection_config
- connection_pool.spec.config
- end
-
- def connection_pool
- connection_handler.retrieve_connection_pool(self) or raise ConnectionNotEstablished
- end
-
- def retrieve_connection
- connection_handler.retrieve_connection(self)
- end
-
- # Returns true if Active Record is connected.
- def connected?
- connection_handler.connected?(self)
- end
-
- def remove_connection(klass = self)
- connection_handler.remove_connection(klass)
- end
-
- def clear_active_connections!
- connection_handler.clear_active_connections!
- end
-
- delegate :clear_reloadable_connections!,
- :clear_all_connections!,:verify_active_connections!, :to => :connection_handler
- end
- end
-end
@@ -11,6 +11,7 @@ module ConnectionAdapters # :nodoc:
extend ActiveSupport::Autoload
autoload :Column
+ autoload :ConnectionSpecification
autoload_under 'abstract' do
autoload :IndexDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
@@ -26,7 +27,6 @@ module ConnectionAdapters # :nodoc:
autoload :ConnectionPool
autoload :ConnectionHandler, 'active_record/connection_adapters/abstract/connection_pool'
autoload :ConnectionManagement, 'active_record/connection_adapters/abstract/connection_pool'
- autoload :ConnectionSpecification
autoload :QueryCache
end
@@ -0,0 +1,79 @@
+module ActiveRecord
+ module ConnectionAdapters
+ class ConnectionSpecification #:nodoc:
+ attr_reader :config, :adapter_method
+
+ def initialize (config, adapter_method)
+ @config, @adapter_method = config, adapter_method
+ end
+
+ ##
+ # Builds a ConnectionSpecification from user input
+ class Resolver # :nodoc:
+ attr_reader :config, :klass, :configurations
+
+ def initialize(config, configurations)
+ @config = config
+ @configurations = configurations
+ end
+
+ def spec
+ case config
+ when nil
+ raise AdapterNotSpecified unless defined?(Rails.env)
+ resolve_string_connection Rails.env
+ when Symbol, String
+ resolve_string_connection config.to_s
+ when Hash
+ resolve_hash_connection config
+ end
+ end
+
+ private
+ def resolve_string_connection(spec) # :nodoc:
+ hash = configurations.fetch(spec) do |k|
+ connection_url_to_hash(k)
+ end
+
+ raise(AdapterNotSpecified, "#{spec} database is not configured") unless hash
+
+ resolve_hash_connection hash
+ end
+
+ def resolve_hash_connection(spec) # :nodoc:
+ spec = spec.symbolize_keys
+
+ raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
+
+ begin
+ require "active_record/connection_adapters/#{spec[:adapter]}_adapter"
+ rescue LoadError => e
+ raise LoadError, "Please install the #{spec[:adapter]} adapter: `gem install activerecord-#{spec[:adapter]}-adapter` (#{e.message})", e.backtrace
+ end
+
+ adapter_method = "#{spec[:adapter]}_connection"
+
+ ConnectionSpecification.new(spec, adapter_method)
+ end
+
+ def connection_url_to_hash(url) # :nodoc:
+ config = URI.parse url
+ adapter = config.scheme
+ adapter = "postgresql" if adapter == "postgres"
+ spec = { :adapter => adapter,
+ :username => config.user,
+ :password => config.password,
+ :port => config.port,
+ :database => config.path.sub(%r{^/},""),
+ :host => config.host }
+ spec.reject!{ |_,value| !value }
+ if config.query
+ options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys
+ spec.merge!(options)
+ end
+ spec
+ end
+ end
+ end
+ end
+end
@@ -4,7 +4,7 @@
require 'mysql2'
module ActiveRecord
- module Core::ClassMethods
+ module ConnectionHandling
# Establishes a connection to the database that's used by all Active Record objects.
def mysql2_connection(config)
config[:username] = 'root' if config[:username].nil?
@@ -18,7 +18,7 @@ class Result; include Enumerable end
end
module ActiveRecord
- module Core::ClassMethods
+ module ConnectionHandling
# Establishes a connection to the database that's used by all Active Record objects.
def mysql_connection(config) # :nodoc:
config = config.symbolize_keys
@@ -7,7 +7,7 @@
require 'pg'
module ActiveRecord
- module Core::ClassMethods
+ module ConnectionHandling
# Establishes a connection to the database that's used by all Active Record objects
def postgresql_connection(config) # :nodoc:
config = config.symbolize_keys
@@ -4,7 +4,7 @@
require 'sqlite3'
module ActiveRecord
- module Core::ClassMethods
+ module ConnectionHandling
# sqlite3 adapter reuses sqlite_connection.
def sqlite3_connection(config) # :nodoc:
# Require database.
Oops, something went wrong.

0 comments on commit dae7b65

Please sign in to comment.