提交 6af7192a 编写于 作者: J Jon Leighton

I herd you like modules.

上级 b2c9ce34
......@@ -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
......@@ -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
......
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 <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 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 <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
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.
......
......@@ -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
......
......@@ -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]
......
......@@ -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
......
......@@ -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"
......
......@@ -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
......
......@@ -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
......
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)
......@@ -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
......
require "cases/helper"
module ActiveRecord
class Base
module Core
class ConnectionSpecification
class ResolverTest < ActiveRecord::TestCase
def resolve(spec)
......
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
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
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册