diff options
-rw-r--r-- | activerecord/CHANGELOG | 10 | ||||
-rwxr-xr-x | activerecord/lib/active_record/associations.rb | 4 | ||||
-rwxr-xr-x | activerecord/lib/active_record/base.rb | 19 | ||||
-rw-r--r-- | activerecord/test/fixtures/project.rb | 6 | ||||
-rwxr-xr-x | activerecord/test/fixtures/topic.rb | 2 | ||||
-rwxr-xr-x | activerecord/test/inheritance_test.rb | 34 |
6 files changed, 59 insertions, 16 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index a3f20d4c6e..838d8d252a 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,15 @@ *CVS* +* Added a better exception for when a type column is used in a table without the intention of triggering single-table inheritance. Example: + + ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'bad_class!'. + This error is raised because the column 'type' is reserved for storing the class in case of inheritance. + Please rename this column if you didn't intend it to be used for storing the inheritance class or + overwrite Company.inheritance_column to use another column for that information. + +* Added that single-table inheritance will only kick in if the inheritance_column (by default "type") is present. Otherwise, inheritance won't + have any magic side effects. + * Added the possibility of marking fields as being in error without adding a message (using nil) to it that'll get displayed wth full_messages #208 [mjobin] * Fixed Base.errors to be indifferent as to whether strings or symbols are used. Examples: diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index c51210ef1f..ba7f34d729 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -581,7 +581,9 @@ module ActiveRecord end def require_association_class(class_name) - begin + return unless class_name + + begin require_association(Inflector.underscore(class_name)) rescue LoadError # Failed to load the associated class -- let's hope the developer is doing the requiring himself. diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 046819f7bb..899db1af10 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -6,6 +6,8 @@ require 'yaml' module ActiveRecord #:nodoc: class ActiveRecordError < StandardError #:nodoc: end + class SubclassNotFound < ActiveRecordError #:nodoc: + end class AssociationTypeMismatch < ActiveRecordError #:nodoc: end class SerializationTypeMismatch < ActiveRecordError #:nodoc: @@ -535,7 +537,7 @@ module ActiveRecord #:nodoc: end def descends_from_active_record? # :nodoc: - superclass == Base + superclass == Base || !columns_hash.has_key?(inheritance_column) end def quote(object) @@ -568,7 +570,20 @@ module ActiveRecord #:nodoc: # Finder methods must instantiate through this method to work with the single-table inheritance model # that makes it possible to create objects of different types from the same table. def instantiate(record) - object = record_with_type?(record) ? compute_type(record[inheritance_column]).allocate : allocate + require_association_class(record[inheritance_column]) + + begin + object = record_with_type?(record) ? compute_type(record[inheritance_column]).allocate : allocate + rescue NameError + raise( + SubclassNotFound, + "The single-table inheritance mechanism failed to locate the subclass: '#{record[inheritance_column]}'. " + + "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " + + "Please rename this column if you didn't intend it to be used for storing the inheritance class " + + "or overwrite #{self.to_s}.inheritance_column to use another column for that information." + ) + end + object.instance_variable_set("@attributes", record) return object end diff --git a/activerecord/test/fixtures/project.rb b/activerecord/test/fixtures/project.rb index 1ccf39d7cf..fddea7b61c 100644 --- a/activerecord/test/fixtures/project.rb +++ b/activerecord/test/fixtures/project.rb @@ -1,4 +1,10 @@ class Project < ActiveRecord::Base has_and_belongs_to_many :developers, :uniq => true has_and_belongs_to_many :developers_named_david, :class_name => "Developer", :conditions => "name = 'David'", :uniq => true +end + +class SpecialProject < Project + def hello_world + "hello there!" + end end
\ No newline at end of file diff --git a/activerecord/test/fixtures/topic.rb b/activerecord/test/fixtures/topic.rb index 60022aa46b..4c46122450 100755 --- a/activerecord/test/fixtures/topic.rb +++ b/activerecord/test/fixtures/topic.rb @@ -3,7 +3,7 @@ class Topic < ActiveRecord::Base serialize :content before_create :default_written_on - before_destroy :destroy_children #'self.class.delete_all "parent_id = #{id}"' + before_destroy :destroy_children def parent self.class.find(parent_id) diff --git a/activerecord/test/inheritance_test.rb b/activerecord/test/inheritance_test.rb index 6f8175801d..e595ed1e92 100755 --- a/activerecord/test/inheritance_test.rb +++ b/activerecord/test/inheritance_test.rb @@ -1,20 +1,13 @@ require 'abstract_unit' require 'fixtures/company' - +require 'fixtures/project' class InheritanceTest < Test::Unit::TestCase - def setup - @company_fixtures = create_fixtures "companies" - end + fixtures :companies, :projects - def switch_to_alt_inheritance_column - # we don't want misleading test results, so get rid of the values in the type column - Company.find_all(nil, "id").each do |c| - c['type'] = nil - c.save - end - - def Company.inheritance_column() "ruby_type" end + def test_a_bad_type_column + Company.connection.insert "INSERT INTO companies (id, type, name) VALUES(100, 'bad_class!', 'Not happening')" + assert_raises(ActiveRecord::SubclassNotFound) { Company.find(100) } end def test_inheritance_find @@ -122,4 +115,21 @@ class InheritanceTest < Test::Unit::TestCase switch_to_alt_inheritance_column test_complex_inheritance end + + def test_inheritance_without_mapping + assert_kind_of SpecialProject, SpecialProject.find(1) + assert_nothing_raised { SpecialProject.create("name" => "And breaaaaathe!") } + + end + + private + def switch_to_alt_inheritance_column + # we don't want misleading test results, so get rid of the values in the type column + Company.find_all(nil, "id").each do |c| + c['type'] = nil + c.save + end + + def Company.inheritance_column() "ruby_type" end + end end
\ No newline at end of file |