diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 914709e761c9c685e8e47f8ac9bf154c407ff3cf..e461e2ecc6dcbef053c575825b8b339a9b28a559 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -328,5 +328,7 @@ module ActiveRecord #:nodoc:
# instances in the current object space.
class Base
include ActiveRecord::Model
+
+ self.connection_handler = ConnectionAdapters::ConnectionHandler.new
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 401398c56b9ed17839b621541ee50b30402b78c4..f69a14f7406369765fedcb778996cba66305b048 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -371,7 +371,12 @@ def retrieve_connection_pool(klass)
pool = @class_to_pool[klass.name]
return pool if pool
return nil if ActiveRecord::Base == klass
- retrieve_connection_pool klass.superclass
+
+ if klass.superclass && klass.superclass < Model
+ retrieve_connection_pool klass.superclass
+ else
+ retrieve_connection_pool ActiveRecord::Base
+ end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
index 7145dc069269b012b595de37982530bfde039375..63e402011320a5bf04d4a51788b11f3e904f4ef0 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
@@ -1,5 +1,7 @@
+require 'active_support/core_ext/module/delegation'
+
module ActiveRecord
- class Base
+ module Core
class ConnectionSpecification #:nodoc:
attr_reader :config, :adapter_method
def initialize (config, adapter_method)
@@ -75,12 +77,6 @@ def connection_url_to_hash(url) # :nodoc:
end
end
- ##
- # :singleton-method:
- # The connection handler
- class_attribute :connection_handler, :instance_writer => false
- self.connection_handler = ConnectionAdapters::ConnectionHandler.new
-
# 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.
@@ -88,53 +84,53 @@ def connection
self.class.connection
end
- # Establishes the connection to the database. Accepts a hash as input where
- # the :adapter 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 self.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
+ module ClassMethods
+ # Establishes the connection to the database. Accepts a hash as input where
+ # the :adapter 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
+ remove_connection
+ connection_handler.establish_connection name, spec
+ end
- class << self
# 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.
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 626571a9480b1c1c7c82588cf0c5b3da001c6224..e51796871ad3bfc685774527548e97152584a89c 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -4,9 +4,9 @@
require 'mysql2'
module ActiveRecord
- class Base
+ module Core::ClassMethods
# Establishes a connection to the database that's used by all Active Record objects.
- def self.mysql2_connection(config)
+ def mysql2_connection(config)
config[:username] = 'root' if config[:username].nil?
if Mysql2::Client.const_defined? :FOUND_ROWS
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index f092edecda5fc76603fa2374f1ab060824350119..3eec59b5a4b76779138ba402cc451ee696ba5e8a 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -18,9 +18,9 @@ class Result; include Enumerable end
end
module ActiveRecord
- class Base
+ module Core::ClassMethods
# Establishes a connection to the database that's used by all Active Record objects.
- def self.mysql_connection(config) # :nodoc:
+ def mysql_connection(config) # :nodoc:
config = config.symbolize_keys
host = config[:host]
port = config[:port]
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index d7adcdc5d4661f7a8995461bee0543ef5fb22841..74a9be99bde4fec8c25628f85e0ab5b416d0fb19 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -7,9 +7,9 @@
require 'pg'
module ActiveRecord
- class Base
+ module Core::ClassMethods
# Establishes a connection to the database that's used by all Active Record objects
- def self.postgresql_connection(config) # :nodoc:
+ def postgresql_connection(config) # :nodoc:
config = config.symbolize_keys
host = config[:host]
port = config[:port] || 5432
@@ -876,7 +876,7 @@ def indexes(table_name, name = nil)
# add info on sort order for columns (only desc order is explicitly specified, asc is the default)
desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {}
-
+
column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names, [], orders)
end.compact
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 11bb457d033030c62adf11985c51cf8662744703..ac3fb72b6e72f2421abf8d2a11a62caa43acdea8 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -4,9 +4,9 @@
require 'sqlite3'
module ActiveRecord
- class Base
+ module Core::ClassMethods
# sqlite3 adapter reuses sqlite_connection.
- def self.sqlite3_connection(config) # :nodoc:
+ def sqlite3_connection(config) # :nodoc:
# Require database.
unless config[:database]
raise ArgumentError, "No database file specified. Missing argument: database"
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index dfd239a9982672f176c62f430ca1fdc5206501c0..84ac6dd93d4d6e5b2904aa99f4b9540790db03eb 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -65,6 +65,11 @@ module Core
# Specify whether or not to use timestamps for migration versions
cattr_accessor :timestamped_migrations , :instance_writer => false
self.timestamped_migrations = true
+
+ ##
+ # :singleton-method:
+ # The connection handler
+ class_attribute :connection_handler, :instance_writer => false
end
module ClassMethods
@@ -111,7 +116,13 @@ def arel_engine
if self == ActiveRecord::Base
ActiveRecord::Base
else
- connection_handler.connection_pools[name] ? self : superclass.arel_engine
+ if connection_handler.connection_pools[name]
+ self
+ elsif superclass < ActiveRecord::Model
+ superclass.arel_engine
+ else
+ ActiveRecord::Base
+ end
end
end
end
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index de9461982aaa4dd1269d091335819490cd3f2102..9b73c0d33cdf2db836f1ba9693214b7b87058f48 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -13,7 +13,9 @@ module Inheritance
module ClassMethods
# True if this isn't a concrete subclass needing a STI type condition.
def descends_from_active_record?
- if superclass.abstract_class?
+ if !(superclass < Model)
+ true
+ elsif superclass.abstract_class?
superclass.descends_from_active_record?
else
superclass == Base || !columns_hash.include?(inheritance_column)
@@ -84,10 +86,14 @@ def instantiate(record)
# Returns the class descending directly from ActiveRecord::Base or an
# abstract class, if any, in the inheritance hierarchy.
def class_of_active_record_descendant(klass)
- if klass == Base || klass.superclass == Base || klass.superclass.abstract_class?
- klass
- elsif klass.superclass.nil?
+ unless klass < Model::Tag
raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
+ end
+
+ if klass == Base || klass.superclass == Base ||
+ klass.superclass < Model::Tag && klass.superclass.abstract_class? ||
+ !(klass.superclass < Model::Tag)
+ klass
else
class_of_active_record_descendant(klass.superclass)
end
diff --git a/activerecord/lib/active_record/model.rb b/activerecord/lib/active_record/model.rb
index 6643c3bf5a2dd19d1f6a53360c66b3be75b91b04..9a8f7a93b6453e5593fdcb08f928914e35d612a6 100644
--- a/activerecord/lib/active_record/model.rb
+++ b/activerecord/lib/active_record/model.rb
@@ -1,7 +1,14 @@
module ActiveRecord
module Model
+ # So we can recognise an AR class even while self.included is being
+ # executed. (At that time, klass < Model == false.)
+ module Tag #:nodoc:
+ end
+
def self.included(base)
base.class_eval do
+ include Tag
+
include ActiveRecord::Persistence
extend ActiveModel::Naming
extend QueryCache::ClassMethods
@@ -35,10 +42,12 @@ def self.included(base)
include Aggregations, Transactions, Reflection, Serialization, Store
include Core
+
+ self.connection_handler = ActiveRecord::Base.connection_handler
end
end
end
end
require 'active_record/connection_adapters/abstract/connection_specification'
-ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
+ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Model)
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 1de820b3a6c57d779dbbd6cc929068c1b55f4c66..5fd0b12706ef19fc8450d617f5836f6de0a45fe9 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -128,7 +128,7 @@ def quoted_table_name
# Computes the table name, (re)sets it internally, and returns it.
def reset_table_name #:nodoc:
- if superclass.abstract_class?
+ if (superclass < ActiveRecord::Model) && superclass.abstract_class?
self.table_name = superclass.table_name || compute_table_name
elsif abstract_class?
self.table_name = superclass == Base ? nil : superclass.table_name
@@ -143,7 +143,7 @@ def full_table_name_prefix #:nodoc:
# The name of the column containing the object's class when Single Table Inheritance is used
def inheritance_column
- if self == Base
+ if self == Base || !(superclass < Model)
'type'
else
(@inheritance_column ||= nil) || superclass.inheritance_column
diff --git a/activerecord/test/cases/connection_specification/resolver_test.rb b/activerecord/test/cases/connection_specification/resolver_test.rb
index d4b0f236ee96826787506146c01daf054da1dd77..5f9a742285b299945e9962892e13e03bf6ddfcca 100644
--- a/activerecord/test/cases/connection_specification/resolver_test.rb
+++ b/activerecord/test/cases/connection_specification/resolver_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
module ActiveRecord
- class Base
+ module Core
class ConnectionSpecification
class ResolverTest < ActiveRecord::TestCase
def resolve(spec)
diff --git a/activerecord/test/cases/inclusion_test.rb b/activerecord/test/cases/inclusion_test.rb
new file mode 100644
index 0000000000000000000000000000000000000000..07d538f6bc7f9ef3a9f3580b762884f1985bc98f
--- /dev/null
+++ b/activerecord/test/cases/inclusion_test.rb
@@ -0,0 +1,36 @@
+require 'cases/helper'
+require 'models/teapot'
+
+class BasicInclusionModelTest < ActiveRecord::TestCase
+ def test_basic_model
+ Teapot.create!(:name => "Ronnie Kemper")
+ assert_equal "Ronnie Kemper", Teapot.find(1).name
+ end
+end
+
+class InclusionUnitTest < ActiveRecord::TestCase
+ def setup
+ @klass = Class.new { include ActiveRecord::Model }
+ end
+
+ def test_non_abstract_class
+ assert !@klass.abstract_class?
+ end
+
+ def test_abstract_class
+ @klass.abstract_class = true
+ assert @klass.abstract_class?
+ end
+
+ def test_establish_connection
+ assert @klass.respond_to?(:establish_connection)
+ end
+
+ def test_adapter_connection
+ assert @klass.respond_to?("#{ActiveRecord::Base.connection_config[:adapter]}_connection")
+ end
+
+ def test_connection_handler
+ assert_equal ActiveRecord::Base.connection_handler, @klass.connection_handler
+ end
+end
diff --git a/activerecord/test/models/teapot.rb b/activerecord/test/models/teapot.rb
new file mode 100644
index 0000000000000000000000000000000000000000..638a1b38f843133e7fdc6b95a6f4d60cb0457acf
--- /dev/null
+++ b/activerecord/test/models/teapot.rb
@@ -0,0 +1,13 @@
+class Teapot
+ # I'm a little teapot,
+ # Short and stout,
+ # Here is my handle
+ # Here is my spout
+ # When I get all steamed up,
+ # Hear me shout,
+ # Tip me over and pour me out!
+ #
+ # HELL YEAH TEAPOT SONG
+
+ include ActiveRecord::Model
+end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 5933e1f46e9dd74e6563cff40f44c4ffc74bb79d..09c8c25d7487a4838c2118e31e96dbf04c318b3d 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -596,6 +596,10 @@ def create_table(*args, &block)
t.datetime :ending
end
+ create_table :teapots, :force => true do |t|
+ t.string :name
+ end
+
create_table :topics, :force => true do |t|
t.string :title
t.string :author_name