diff options
-rw-r--r-- | activerecord/CHANGELOG | 2 | ||||
-rwxr-xr-x | activerecord/lib/active_record/base.rb | 9 | ||||
-rwxr-xr-x | activerecord/test/base_test.rb | 57 | ||||
-rwxr-xr-x | activerecord/test/fixtures/db_definitions/mysql.sql | 6 | ||||
-rw-r--r-- | activerecord/test/fixtures/db_definitions/sqlite.sql | 4 | ||||
-rw-r--r-- | activerecord/test/fixtures/post.rb | 3 |
6 files changed, 70 insertions, 11 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 446bbec2ee..2d7b9820ed 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Subclasses of an abstract class work with single-table inheritance. #5704 [nick+rails@ag.arizona.edu, Ryan Davis, Jeremy Kemper] + * Change fixture_path to a class inheritable accessor allowing test cases to have their own custom set of fixtures. #6672 [zdennis] * Quote ActiveSupport::Multibyte::Chars. #6653 [Julian Tarkhanov] diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 99c276ef8b..08df7e6f2e 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -816,7 +816,7 @@ module ActiveRecord #:nodoc: end def descends_from_active_record? # :nodoc: - superclass == Base || !columns_hash.include?(inheritance_column) + superclass.abstract_class? || !columns_hash.include?(inheritance_column) end @@ -1161,7 +1161,7 @@ module ActiveRecord #:nodoc: segments = [] segments << sanitize_sql(scope[:conditions]) if scope && scope[:conditions] segments << sanitize_sql(conditions) unless conditions.nil? - segments << type_condition unless descends_from_active_record? + segments << type_condition unless descends_from_active_record? segments.compact! sql << "WHERE (#{segments.join(") AND (")}) " unless segments.empty? end @@ -1362,7 +1362,7 @@ module ActiveRecord #:nodoc: # Returns the class descending directly from ActiveRecord in the inheritance hierarchy. def class_of_active_record_descendant(klass) - if klass.superclass == Base || klass.superclass.abstract_class? + if klass.superclass.abstract_class? klass elsif klass.superclass.nil? raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord" @@ -1483,6 +1483,9 @@ module ActiveRecord #:nodoc: end end + # ActiveRecord::Base is abstract. + self.abstract_class = true + public # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with # attributes but not yet saved (pass a hash with key names matching the associated table column names). diff --git a/activerecord/test/base_test.rb b/activerecord/test/base_test.rb index 8cd17d7034..3eb5a676a4 100755 --- a/activerecord/test/base_test.rb +++ b/activerecord/test/base_test.rb @@ -10,6 +10,7 @@ require 'fixtures/auto_id' require 'fixtures/column_name' require 'fixtures/subscriber' require 'fixtures/keyboard' +require 'fixtures/post' class Category < ActiveRecord::Base; end class Smarts < ActiveRecord::Base; end @@ -28,8 +29,9 @@ class NonExistentTable < ActiveRecord::Base; end class TestOracleDefault < ActiveRecord::Base; end class LoosePerson < ActiveRecord::Base - attr_protected :credit_rating, :administrator + self.table_name = 'people' self.abstract_class = true + attr_protected :credit_rating, :administrator end class LooseDescendant < LoosePerson @@ -37,6 +39,7 @@ class LooseDescendant < LoosePerson end class TightPerson < ActiveRecord::Base + self.table_name = 'people' attr_accessible :name, :address end @@ -1361,13 +1364,63 @@ class BasicsTest < Test::Unit::TestCase end end - def test_base_class + def test_abstract_class + assert ActiveRecord::Base.abstract_class? assert LoosePerson.abstract_class? assert !LooseDescendant.abstract_class? + end + + def test_base_class assert_equal LoosePerson, LoosePerson.base_class assert_equal LooseDescendant, LooseDescendant.base_class assert_equal TightPerson, TightPerson.base_class assert_equal TightPerson, TightDescendant.base_class + + assert_equal Post, Post.base_class + assert_equal Post, SpecialPost.base_class + assert_equal Post, StiPost.base_class + assert_equal SubStiPost, SubStiPost.base_class + end + + def test_descends_from_active_record + # Tries to call Object.abstract_class? + assert_raise(NoMethodError) do + ActiveRecord::Base.descends_from_active_record? + end + + # Abstract subclass of AR::Base. + assert LoosePerson.descends_from_active_record? + + # Concrete subclass of an abstract class. + assert LooseDescendant.descends_from_active_record? + + # Concrete subclass of AR::Base. + assert TightPerson.descends_from_active_record? + + # Concrete subclass of a concrete class but has no type column. + assert TightDescendant.descends_from_active_record? + + # Concrete subclass of AR::Base. + assert Post.descends_from_active_record? + + # Abstract subclass of a concrete class which has a type column. + # This is pathological, as you'll never have Sub < Abstract < Concrete. + assert !StiPost.descends_from_active_record? + + # Concrete subclasses an abstract class which has a type column. + assert SubStiPost.descends_from_active_record? + end + + def test_find_on_abstract_base_class_doesnt_use_type_condition + old_class = LooseDescendant + Object.send :remove_const, :LooseDescendant + + descendant = old_class.create! + assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}" + ensure + unless Object.const_defined?(:LooseDescendant) + Object.const_set :LooseDescendant, old_class + end end def test_assert_queries diff --git a/activerecord/test/fixtures/db_definitions/mysql.sql b/activerecord/test/fixtures/db_definitions/mysql.sql index c6a78962c6..9e5cf72aba 100755 --- a/activerecord/test/fixtures/db_definitions/mysql.sql +++ b/activerecord/test/fixtures/db_definitions/mysql.sql @@ -159,14 +159,14 @@ CREATE TABLE `posts` ( `author_id` INTEGER, `title` VARCHAR(255) NOT NULL, `body` TEXT NOT NULL, - `type` VARCHAR(255) NOT NULL + `type` VARCHAR(255) default NULL ) TYPE=InnoDB; CREATE TABLE `comments` ( `id` INTEGER NOT NULL auto_increment PRIMARY KEY, `post_id` INTEGER NOT NULL, `body` TEXT NOT NULL, - `type` VARCHAR(255) NOT NULL + `type` VARCHAR(255) default NULL ) TYPE=InnoDB; CREATE TABLE `authors` ( @@ -184,7 +184,7 @@ CREATE TABLE `tasks` ( CREATE TABLE `categories` ( `id` int(11) NOT NULL auto_increment, `name` VARCHAR(255) NOT NULL, - `type` VARCHAR(255) NOT NULL, + `type` VARCHAR(255) default NULL, PRIMARY KEY (`id`) ) TYPE=InnoDB; diff --git a/activerecord/test/fixtures/db_definitions/sqlite.sql b/activerecord/test/fixtures/db_definitions/sqlite.sql index 8f89c419a1..edf1e815da 100644 --- a/activerecord/test/fixtures/db_definitions/sqlite.sql +++ b/activerecord/test/fixtures/db_definitions/sqlite.sql @@ -144,14 +144,14 @@ CREATE TABLE 'posts' ( 'id' INTEGER NOT NULL PRIMARY KEY, 'author_id' INTEGER, 'title' VARCHAR(255) NOT NULL, - 'type' VARCHAR(255) NOT NULL, + 'type' VARCHAR(255) DEFAULT NULL, 'body' TEXT NOT NULL ); CREATE TABLE 'comments' ( 'id' INTEGER NOT NULL PRIMARY KEY, 'post_id' INTEGER NOT NULL, - 'type' VARCHAR(255) NOT NULL, + 'type' VARCHAR(255) DEFAULT NULL, 'body' TEXT NOT NULL ); diff --git a/activerecord/test/fixtures/post.rb b/activerecord/test/fixtures/post.rb index 9dc18441d0..44ac3c1053 100644 --- a/activerecord/test/fixtures/post.rb +++ b/activerecord/test/fixtures/post.rb @@ -46,7 +46,7 @@ class Post < ActiveRecord::Base end end -class SpecialPost < Post; end; +class SpecialPost < Post; end class StiPost < Post self.abstract_class = true @@ -54,4 +54,5 @@ class StiPost < Post end class SubStiPost < StiPost + self.table_name = Post.table_name end |