mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
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.
This commit is contained in:
parent
93c1f11c0a
commit
dae7b65453
25 changed files with 251 additions and 230 deletions
|
@ -59,6 +59,7 @@ module ActiveRecord
|
||||||
autoload :Callbacks
|
autoload :Callbacks
|
||||||
autoload :Core
|
autoload :Core
|
||||||
autoload :CounterCache
|
autoload :CounterCache
|
||||||
|
autoload :ConnectionHandling
|
||||||
autoload :DynamicMatchers
|
autoload :DynamicMatchers
|
||||||
autoload :DynamicFinderMatch
|
autoload :DynamicFinderMatch
|
||||||
autoload :DynamicScopeMatch
|
autoload :DynamicScopeMatch
|
||||||
|
|
|
@ -61,7 +61,7 @@ module ActiveRecord
|
||||||
raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord"
|
raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord"
|
||||||
end
|
end
|
||||||
|
|
||||||
if active_record_super == Base
|
if [Base, Model].include?(active_record_super)
|
||||||
super
|
super
|
||||||
else
|
else
|
||||||
# If B < A and A defines its own attribute method, then we don't want to overwrite that.
|
# If B < A and A defines its own attribute method, then we don't want to overwrite that.
|
||||||
|
|
|
@ -331,5 +331,4 @@ module ActiveRecord #:nodoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'active_record/connection_adapters/abstract/connection_specification'
|
|
||||||
ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Model::DeprecationProxy)
|
ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Model::DeprecationProxy)
|
||||||
|
|
|
@ -370,7 +370,7 @@ connection. For example: ActiveRecord::Base.connection.close
|
||||||
def retrieve_connection_pool(klass)
|
def retrieve_connection_pool(klass)
|
||||||
pool = @class_to_pool[klass.name]
|
pool = @class_to_pool[klass.name]
|
||||||
return pool if pool
|
return pool if pool
|
||||||
return nil if ActiveRecord::Base == klass
|
return nil if ActiveRecord::Model == klass
|
||||||
retrieve_connection_pool klass.active_record_super
|
retrieve_connection_pool klass.active_record_super
|
||||||
end
|
end
|
||||||
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 ActiveRecord
|
||||||
extend ActiveSupport::Autoload
|
extend ActiveSupport::Autoload
|
||||||
|
|
||||||
autoload :Column
|
autoload :Column
|
||||||
|
autoload :ConnectionSpecification
|
||||||
|
|
||||||
autoload_under 'abstract' do
|
autoload_under 'abstract' do
|
||||||
autoload :IndexDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
|
autoload :IndexDefinition, 'active_record/connection_adapters/abstract/schema_definitions'
|
||||||
|
@ -26,7 +27,6 @@ module ActiveRecord
|
||||||
autoload :ConnectionPool
|
autoload :ConnectionPool
|
||||||
autoload :ConnectionHandler, 'active_record/connection_adapters/abstract/connection_pool'
|
autoload :ConnectionHandler, 'active_record/connection_adapters/abstract/connection_pool'
|
||||||
autoload :ConnectionManagement, 'active_record/connection_adapters/abstract/connection_pool'
|
autoload :ConnectionManagement, 'active_record/connection_adapters/abstract/connection_pool'
|
||||||
autoload :ConnectionSpecification
|
|
||||||
|
|
||||||
autoload :QueryCache
|
autoload :QueryCache
|
||||||
end
|
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 @@ gem 'mysql2', '~> 0.3.10'
|
||||||
require 'mysql2'
|
require 'mysql2'
|
||||||
|
|
||||||
module ActiveRecord
|
module ActiveRecord
|
||||||
module Core::ClassMethods
|
module ConnectionHandling
|
||||||
# Establishes a connection to the database that's used by all Active Record objects.
|
# Establishes a connection to the database that's used by all Active Record objects.
|
||||||
def mysql2_connection(config)
|
def mysql2_connection(config)
|
||||||
config[:username] = 'root' if config[:username].nil?
|
config[:username] = 'root' if config[:username].nil?
|
||||||
|
|
|
@ -18,7 +18,7 @@ class Mysql
|
||||||
end
|
end
|
||||||
|
|
||||||
module ActiveRecord
|
module ActiveRecord
|
||||||
module Core::ClassMethods
|
module ConnectionHandling
|
||||||
# Establishes a connection to the database that's used by all Active Record objects.
|
# Establishes a connection to the database that's used by all Active Record objects.
|
||||||
def mysql_connection(config) # :nodoc:
|
def mysql_connection(config) # :nodoc:
|
||||||
config = config.symbolize_keys
|
config = config.symbolize_keys
|
||||||
|
|
|
@ -7,7 +7,7 @@ gem 'pg', '~> 0.11'
|
||||||
require 'pg'
|
require 'pg'
|
||||||
|
|
||||||
module ActiveRecord
|
module ActiveRecord
|
||||||
module Core::ClassMethods
|
module ConnectionHandling
|
||||||
# Establishes a connection to the database that's used by all Active Record objects
|
# Establishes a connection to the database that's used by all Active Record objects
|
||||||
def postgresql_connection(config) # :nodoc:
|
def postgresql_connection(config) # :nodoc:
|
||||||
config = config.symbolize_keys
|
config = config.symbolize_keys
|
||||||
|
|
|
@ -4,7 +4,7 @@ gem 'sqlite3', '~> 1.3.5'
|
||||||
require 'sqlite3'
|
require 'sqlite3'
|
||||||
|
|
||||||
module ActiveRecord
|
module ActiveRecord
|
||||||
module Core::ClassMethods
|
module ConnectionHandling
|
||||||
# sqlite3 adapter reuses sqlite_connection.
|
# sqlite3 adapter reuses sqlite_connection.
|
||||||
def sqlite3_connection(config) # :nodoc:
|
def sqlite3_connection(config) # :nodoc:
|
||||||
# Require database.
|
# Require database.
|
||||||
|
|
100
activerecord/lib/active_record/connection_handling.rb
Normal file
100
activerecord/lib/active_record/connection_handling.rb
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
require 'active_support/core_ext/module/delegation'
|
||||||
|
|
||||||
|
module ActiveRecord
|
||||||
|
module ConnectionHandling
|
||||||
|
# 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 = ConnectionAdapters::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
|
|
@ -119,13 +119,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def arel_engine
|
def arel_engine
|
||||||
@arel_engine ||= begin
|
@arel_engine ||= connection_handler.connection_pools[name] ? self : active_record_super.arel_engine
|
||||||
if self == ActiveRecord::Base
|
|
||||||
ActiveRecord::Base
|
|
||||||
else
|
|
||||||
connection_handler.connection_pools[name] ? self : active_record_super.arel_engine
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -304,6 +298,13 @@ module ActiveRecord
|
||||||
@readonly = true
|
@readonly = true
|
||||||
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
|
||||||
|
|
||||||
# Returns the contents of the record as a nicely formatted string.
|
# Returns the contents of the record as a nicely formatted string.
|
||||||
def inspect
|
def inspect
|
||||||
inspection = if @attributes
|
inspection = if @attributes
|
||||||
|
|
|
@ -17,8 +17,10 @@ module ActiveRecord
|
||||||
|
|
||||||
if sup.abstract_class?
|
if sup.abstract_class?
|
||||||
sup.descends_from_active_record?
|
sup.descends_from_active_record?
|
||||||
|
elsif self == Base
|
||||||
|
false
|
||||||
else
|
else
|
||||||
sup == Base || !columns_hash.include?(inheritance_column)
|
[Base, Model].include?(sup) || !columns_hash.include?(inheritance_column)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -81,18 +83,12 @@ module ActiveRecord
|
||||||
instance
|
instance
|
||||||
end
|
end
|
||||||
|
|
||||||
# If this class includes ActiveRecord::Model then it won't have a
|
# For internal use.
|
||||||
# superclass. So this provides a way to get to the 'root' (ActiveRecord::Base),
|
|
||||||
# through inheritance hierarchy, ending in Base, whether or not that is
|
|
||||||
# actually an ancestor of the class.
|
|
||||||
#
|
#
|
||||||
# Mainly for internal use.
|
# If this class includes ActiveRecord::Model then it won't have a
|
||||||
|
# superclass. So this provides a way to get to the 'root' (ActiveRecord::Model).
|
||||||
def active_record_super #:nodoc:
|
def active_record_super #:nodoc:
|
||||||
if self == Base || superclass && superclass < Model
|
superclass < Model ? superclass : Model
|
||||||
superclass
|
|
||||||
else
|
|
||||||
Base
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
@ -105,7 +101,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
sup = klass.active_record_super
|
sup = klass.active_record_super
|
||||||
if klass == Base || sup == Base || sup.abstract_class?
|
if [Base, Model].include?(klass) || [Base, Model].include?(sup) || sup.abstract_class?
|
||||||
klass
|
klass
|
||||||
else
|
else
|
||||||
class_of_active_record_descendant(sup)
|
class_of_active_record_descendant(sup)
|
||||||
|
|
|
@ -22,6 +22,7 @@ module ActiveRecord
|
||||||
include DynamicMatchers
|
include DynamicMatchers
|
||||||
include CounterCache
|
include CounterCache
|
||||||
include Explain
|
include Explain
|
||||||
|
include ConnectionHandling
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
|
@ -40,6 +41,7 @@ module ActiveRecord
|
||||||
extend ActiveModel::AttributeMethods::ClassMethods
|
extend ActiveModel::AttributeMethods::ClassMethods
|
||||||
extend Callbacks::Register
|
extend Callbacks::Register
|
||||||
extend Explain
|
extend Explain
|
||||||
|
extend ConnectionHandling
|
||||||
|
|
||||||
def self.extend(*modules)
|
def self.extend(*modules)
|
||||||
ClassMethods.send(:include, *modules)
|
ClassMethods.send(:include, *modules)
|
||||||
|
@ -65,6 +67,20 @@ module ActiveRecord
|
||||||
include Aggregations, Transactions, Reflection, Serialization, Store
|
include Aggregations, Transactions, Reflection, Serialization, Store
|
||||||
include Core
|
include Core
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def arel_engine
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def abstract_class?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def inheritance_column
|
||||||
|
'type'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
module DeprecationProxy #:nodoc:
|
module DeprecationProxy #:nodoc:
|
||||||
class << self
|
class << self
|
||||||
instance_methods.each { |m| undef_method m unless m =~ /^__|^object_id$|^instance_eval$/ }
|
instance_methods.each { |m| undef_method m unless m =~ /^__|^object_id$|^instance_eval$/ }
|
||||||
|
|
|
@ -143,12 +143,8 @@ module ActiveRecord
|
||||||
|
|
||||||
# The name of the column containing the object's class when Single Table Inheritance is used
|
# The name of the column containing the object's class when Single Table Inheritance is used
|
||||||
def inheritance_column
|
def inheritance_column
|
||||||
if self == Base
|
|
||||||
'type'
|
|
||||||
else
|
|
||||||
(@inheritance_column ||= nil) || active_record_super.inheritance_column
|
(@inheritance_column ||= nil) || active_record_super.inheritance_column
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# Sets the value of inheritance_column
|
# Sets the value of inheritance_column
|
||||||
def inheritance_column=(value)
|
def inheritance_column=(value)
|
||||||
|
|
|
@ -23,6 +23,7 @@ require 'models/edge'
|
||||||
require 'models/joke'
|
require 'models/joke'
|
||||||
require 'models/bulb'
|
require 'models/bulb'
|
||||||
require 'models/bird'
|
require 'models/bird'
|
||||||
|
require 'models/teapot'
|
||||||
require 'rexml/document'
|
require 'rexml/document'
|
||||||
require 'active_support/core_ext/exception'
|
require 'active_support/core_ext/exception'
|
||||||
require 'bcrypt'
|
require 'bcrypt'
|
||||||
|
@ -1634,10 +1635,7 @@ class BasicsTest < ActiveRecord::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_descends_from_active_record
|
def test_descends_from_active_record
|
||||||
# Tries to call Object.abstract_class?
|
assert !ActiveRecord::Base.descends_from_active_record?
|
||||||
assert_raise(NoMethodError) do
|
|
||||||
ActiveRecord::Base.descends_from_active_record?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Abstract subclass of AR::Base.
|
# Abstract subclass of AR::Base.
|
||||||
assert LoosePerson.descends_from_active_record?
|
assert LoosePerson.descends_from_active_record?
|
||||||
|
@ -1660,6 +1658,10 @@ class BasicsTest < ActiveRecord::TestCase
|
||||||
|
|
||||||
# Concrete subclasses an abstract class which has a type column.
|
# Concrete subclasses an abstract class which has a type column.
|
||||||
assert !SubStiPost.descends_from_active_record?
|
assert !SubStiPost.descends_from_active_record?
|
||||||
|
|
||||||
|
assert Teapot.descends_from_active_record?
|
||||||
|
assert !OtherTeapot.descends_from_active_record?
|
||||||
|
assert CoolTeapot.descends_from_active_record?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_find_on_abstract_base_class_doesnt_use_type_condition
|
def test_find_on_abstract_base_class_doesnt_use_type_condition
|
||||||
|
@ -1893,4 +1895,13 @@ class BasicsTest < ActiveRecord::TestCase
|
||||||
Bird.stubs(:scoped).returns(mock(:uniq => scope))
|
Bird.stubs(:scoped).returns(mock(:uniq => scope))
|
||||||
assert_equal scope, Bird.uniq
|
assert_equal scope, Bird.uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_active_record_super
|
||||||
|
assert_equal ActiveRecord::Model, ActiveRecord::Base.active_record_super
|
||||||
|
assert_equal ActiveRecord::Base, Topic.active_record_super
|
||||||
|
assert_equal Topic, ImportantTopic.active_record_super
|
||||||
|
assert_equal ActiveRecord::Model, Teapot.active_record_super
|
||||||
|
assert_equal Teapot, OtherTeapot.active_record_super
|
||||||
|
assert_equal ActiveRecord::Model, CoolTeapot.active_record_super
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,7 +35,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_close
|
def test_close
|
||||||
pool = ConnectionPool.new(Base::ConnectionSpecification.new({}, nil))
|
pool = ConnectionPool.new(ConnectionSpecification.new({}, nil))
|
||||||
pool.connections << adapter
|
pool.connections << adapter
|
||||||
adapter.pool = pool
|
adapter.pool = pool
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require "cases/helper"
|
require "cases/helper"
|
||||||
|
|
||||||
module ActiveRecord
|
module ActiveRecord
|
||||||
module Core
|
module ConnectionAdapters
|
||||||
class ConnectionSpecification
|
class ConnectionSpecification
|
||||||
class ResolverTest < ActiveRecord::TestCase
|
class ResolverTest < ActiveRecord::TestCase
|
||||||
def resolve(spec)
|
def resolve(spec)
|
||||||
|
|
|
@ -56,10 +56,13 @@ class InclusionUnitTest < ActiveRecord::TestCase
|
||||||
|
|
||||||
def test_establish_connection
|
def test_establish_connection
|
||||||
assert @klass.respond_to?(:establish_connection)
|
assert @klass.respond_to?(:establish_connection)
|
||||||
|
assert ActiveRecord::Model.respond_to?(:establish_connection)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_adapter_connection
|
def test_adapter_connection
|
||||||
assert @klass.respond_to?("#{ActiveRecord::Base.connection_config[:adapter]}_connection")
|
name = "#{ActiveRecord::Base.connection_config[:adapter]}_connection"
|
||||||
|
assert @klass.respond_to?(name)
|
||||||
|
assert ActiveRecord::Model.respond_to?(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_connection_handler
|
def test_connection_handler
|
||||||
|
|
|
@ -65,7 +65,6 @@ class InheritanceTest < ActiveRecord::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_company_descends_from_active_record
|
def test_company_descends_from_active_record
|
||||||
assert_raise(NoMethodError) { ActiveRecord::Base.descends_from_active_record? }
|
|
||||||
assert AbstractCompany.descends_from_active_record?, 'AbstractCompany should descend from ActiveRecord::Base'
|
assert AbstractCompany.descends_from_active_record?, 'AbstractCompany should descend from ActiveRecord::Base'
|
||||||
assert Company.descends_from_active_record?, 'Company should descend from ActiveRecord::Base'
|
assert Company.descends_from_active_record?, 'Company should descend from ActiveRecord::Base'
|
||||||
assert !Class.new(Company).descends_from_active_record?, 'Company subclass should not descend from ActiveRecord::Base'
|
assert !Class.new(Company).descends_from_active_record?, 'Company subclass should not descend from ActiveRecord::Base'
|
||||||
|
|
|
@ -7,13 +7,13 @@ class TestUnconnectedAdapter < ActiveRecord::TestCase
|
||||||
self.use_transactional_fixtures = false
|
self.use_transactional_fixtures = false
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@underlying = ActiveRecord::Base.connection
|
@underlying = ActiveRecord::Model.connection
|
||||||
@specification = ActiveRecord::Base.remove_connection
|
@specification = ActiveRecord::Model.remove_connection
|
||||||
end
|
end
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
@underlying = nil
|
@underlying = nil
|
||||||
ActiveRecord::Base.establish_connection(@specification)
|
ActiveRecord::Model.establish_connection(@specification)
|
||||||
load_schema if in_memory_db?
|
load_schema if in_memory_db?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@ class Teapot
|
||||||
include ActiveRecord::Model
|
include ActiveRecord::Model
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class OtherTeapot < Teapot
|
||||||
|
end
|
||||||
|
|
||||||
class OMFGIMATEAPOT
|
class OMFGIMATEAPOT
|
||||||
def aaahhh
|
def aaahhh
|
||||||
"mmm"
|
"mmm"
|
||||||
|
|
|
@ -598,6 +598,7 @@ ActiveRecord::Schema.define do
|
||||||
|
|
||||||
create_table :teapots, :force => true do |t|
|
create_table :teapots, :force => true do |t|
|
||||||
t.string :name
|
t.string :name
|
||||||
|
t.string :type
|
||||||
t.timestamps
|
t.timestamps
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,9 @@ module ARTest
|
||||||
|
|
||||||
def self.connect
|
def self.connect
|
||||||
puts "Using #{connection_name} with Identity Map #{ActiveRecord::IdentityMap.enabled? ? 'on' : 'off'}"
|
puts "Using #{connection_name} with Identity Map #{ActiveRecord::IdentityMap.enabled? ? 'on' : 'off'}"
|
||||||
ActiveRecord::Base.logger = ActiveSupport::Logger.new("debug.log")
|
ActiveRecord::Model.logger = ActiveSupport::Logger.new("debug.log")
|
||||||
ActiveRecord::Base.configurations = connection_config
|
ActiveRecord::Model.configurations = connection_config
|
||||||
ActiveRecord::Base.establish_connection 'arunit'
|
ActiveRecord::Model.establish_connection 'arunit'
|
||||||
Course.establish_connection 'arunit2'
|
Course.establish_connection 'arunit2'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue