aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDiego Carrion <dc.rec1@gmail.com>2015-06-13 12:51:32 -0300
committerDiego Carrion <dc.rec1@gmail.com>2015-06-22 12:38:54 -0300
commit828d0d7a7751a0c6a9faf0c96b89b0ea06a76094 (patch)
tree44fac740ef8548424c137a2d39f28939538996bb
parentebc4c607a7859c9c35246d7fe74a17208ef3a66e (diff)
downloadrails-828d0d7a7751a0c6a9faf0c96b89b0ea06a76094.tar.gz
rails-828d0d7a7751a0c6a9faf0c96b89b0ea06a76094.tar.bz2
rails-828d0d7a7751a0c6a9faf0c96b89b0ea06a76094.zip
thrown ActiveRecord::AssociationTypeMismatch when assigning a wrong value for a namespaced association
fixes #20541
-rw-r--r--activerecord/CHANGELOG.md7
-rw-r--r--activerecord/lib/active_record/associations/association.rb9
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb18
3 files changed, 31 insertions, 3 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 3351013b16..0ec3902eac 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,10 @@
+* Correctly thrown `ActiveRecord::AssociationTypeMismatch` when assigning
+ a wrong value to a namespaced association.
+
+ Fixes #20545
+
+ *Diego Carrion*
+
* `validates_absence_of` respects `marked_for_destruction?`.
Fixes #20449.
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 930f678ae8..7c729676a7 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -211,9 +211,12 @@ module ActiveRecord
# the kind of the class of the associated objects. Meant to be used as
# a sanity check when you are about to assign an associated record.
def raise_on_type_mismatch!(record)
- unless record.is_a?(reflection.klass) || record.is_a?(reflection.class_name.constantize)
- message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
- raise ActiveRecord::AssociationTypeMismatch, message
+ unless record.is_a?(reflection.klass)
+ fresh_class = reflection.class_name.safe_constantize
+ unless fresh_class && record.is_a?(fresh_class)
+ message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
+ raise ActiveRecord::AssociationTypeMismatch, message
+ end
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 039cc46b0b..7726829be4 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -19,6 +19,8 @@ require 'models/invoice'
require 'models/line_item'
require 'models/column'
require 'models/record'
+require 'models/admin'
+require 'models/admin/user'
class BelongsToAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :developers, :projects, :topics,
@@ -151,6 +153,22 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
end
+ def test_type_mismatch_with_namespaced_class
+ assert_nil defined?(Region), "This test should be done with a only namespaced class"
+ ActiveRecord::Base.connection.create_table(:admin_regions) { |t| t.string :name }
+ ActiveRecord::Base.connection.add_column :admin_users, :region_id, :integer
+ Admin.const_set "RegionalUser", Class.new(Admin::User) { belongs_to(:region) }
+ Admin.const_set "Region", Class.new(ActiveRecord::Base)
+ e = assert_raise(ActiveRecord::AssociationTypeMismatch) { Admin::RegionalUser.new(region: 'wrong value') }
+ assert_match(/^Region\([^)]+\) expected, got String\([^)]+\)$/, e.message)
+ ensure
+ Admin.send :remove_const, "Region" if Admin.const_defined?("Region")
+ Admin.send :remove_const, "RegionalUser" if Admin.const_defined?("RegionalUser")
+ connection = ActiveRecord::Base.connection
+ connection.remove_column :admin_users, :region_id if connection.column_exists?(:admin_users, :region_id)
+ connection.drop_table :admin_regions if connection.table_exists?(:admin_regions)
+ end
+
def test_natural_assignment
apple = Firm.create("name" => "Apple")
citibank = Account.create("credit_limit" => 10)