Skip to content

Commit d9b59a0

Browse files
Merge pull request rails#46633 from jonathanhefner/follow-up-46605
Fix association model class error message and error type
2 parents 40255e4 + 336fa48 commit d9b59a0

File tree

7 files changed

+42
-56
lines changed

7 files changed

+42
-56
lines changed

activerecord/lib/active_record/reflection.rb

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -425,15 +425,17 @@ def compute_class(name)
425425

426426
begin
427427
klass = active_record.send(:compute_type, name)
428-
429-
unless klass < ActiveRecord::Base
430-
raise ArgumentError, compute_class_error_message(klass)
431-
end
432-
433-
klass
434428
rescue NameError
435-
raise ArgumentError, compute_class_error_message
429+
message = "Missing model class #{name} for the #{active_record}##{self.name} association."
430+
message += " You can specify a different model class with the :class_name option." unless options[:class_name]
431+
raise NameError, message
432+
end
433+
434+
unless klass < ActiveRecord::Base
435+
raise ArgumentError, "The #{name} model class for the #{active_record}##{self.name} association is not an ActiveRecord::Base subclass."
436436
end
437+
438+
klass
437439
end
438440

439441
attr_reader :type, :foreign_type
@@ -599,16 +601,6 @@ def extensions
599601
end
600602

601603
private
602-
def compute_class_error_message(klass = nil)
603-
msg = +"Rails couldn't find a valid model for the #{name} association. "
604-
if !options[:class_name]
605-
msg << "Use the :class_name option on the association declaration to tell Rails which model to use."
606-
else
607-
msg << "Ensure the class provided to :class_name exists and is an ActiveRecord::Base subclass."
608-
end
609-
msg
610-
end
611-
612604
# Attempts to find the inverse association name automatically.
613605
# If it cannot find a suitable inverse association name, it returns
614606
# +nil+.

activerecord/test/cases/associations_test.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,15 +421,15 @@ class ModelAssociatedToClassesThatDoNotExist < ActiveRecord::Base
421421
end
422422

423423
def test_associations_raise_with_name_error_if_associated_to_classes_that_do_not_exist
424-
assert_raises ArgumentError do
424+
assert_raises NameError do
425425
ModelAssociatedToClassesThatDoNotExist.new.non_existent_has_one_class
426426
end
427427

428-
assert_raises ArgumentError do
428+
assert_raises NameError do
429429
ModelAssociatedToClassesThatDoNotExist.new.non_existent_belongs_to_class
430430
end
431431

432-
assert_raises ArgumentError do
432+
assert_raises NameError do
433433
ModelAssociatedToClassesThatDoNotExist.new.non_existent_has_many_classes
434434
end
435435
end

activerecord/test/cases/finder_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
require "models/customer"
1919
require "models/toy"
2020
require "models/matey"
21-
require "models/dog_lover"
2221
require "models/dog"
2322
require "models/car"
2423
require "models/tyre"

activerecord/test/cases/fixtures_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
require "models/computer"
1818
require "models/course"
1919
require "models/developer"
20-
require "models/dog_lover"
2120
require "models/dog"
2221
require "models/doubloon"
2322
require "models/essay"

activerecord/test/cases/nested_attributes_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
require "cases/helper"
44
require "models/pirate"
5-
require "models/developer"
65
require "models/ship"
76
require "models/ship_part"
87
require "models/bird"

activerecord/test/cases/reflection_test.rb

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -139,50 +139,40 @@ def test_irregular_reflection_class_name
139139
end
140140

141141
def test_reflection_klass_not_found_with_no_class_name_option
142-
[:account_invalid_no_class_name_option,
143-
:info_invalids,
144-
].each do |rel|
145-
expected = <<-MSG.squish
146-
Rails couldn't find a valid model for the #{rel} association.
147-
Use the :class_name option on the association declaration to tell Rails which model to use.
148-
MSG
149-
150-
err = assert_raise(ArgumentError) do
151-
UserWithInvalidRelation.reflect_on_association(rel).klass
152-
end
153-
154-
assert_includes err.message, expected
142+
error = assert_raise(NameError) do
143+
UserWithInvalidRelation.reflect_on_association(:not_a_class).klass
155144
end
145+
146+
assert_match %r/missing/i, error.message
147+
assert_match "NotAClass", error.message
148+
assert_match "UserWithInvalidRelation#not_a_class", error.message
149+
assert_match ":class_name", error.message
156150
end
157151

158152
def test_reflection_klass_not_found_with_pointer_to_non_existent_class_name
159-
expected = <<-MSG.squish
160-
Rails couldn't find a valid model for the class_name_provided_not_a_class association.
161-
Ensure the class provided to :class_name exists and is an ActiveRecord::Base subclass.
162-
MSG
163-
164-
err = assert_raise(ArgumentError) do
153+
error = assert_raise(NameError) do
165154
UserWithInvalidRelation.reflect_on_association(:class_name_provided_not_a_class).klass
166155
end
167156

168-
assert_includes err.message, expected
157+
assert_match %r/missing/i, error.message
158+
assert_match %r/\bNotAClass\b/, error.message
159+
assert_match "UserWithInvalidRelation#class_name_provided_not_a_class", error.message
160+
assert_no_match ":class_name", error.message
169161
end
170162

171163
def test_reflection_klass_requires_ar_subclass
172-
[:account_class_name,
173-
:infos_class_name,
174-
:infos_through_class_name,
164+
[ :account_invalid, # has_one, without :class_name
165+
:account_class_name, # has_one, with :class_name
166+
:info_invalids, # has_many through, without :class_name
167+
:infos_class_name, # has_many through, with :class_name
168+
:infos_through_class_name, # has_many through other :class_name, with :class_name
175169
].each do |rel|
176-
expected = <<-MSG.squish
177-
Rails couldn't find a valid model for the #{rel} association.
178-
Ensure the class provided to :class_name exists and is an ActiveRecord::Base subclass.
179-
MSG
180-
181-
err = assert_raise(ArgumentError) do
170+
error = assert_raise(ArgumentError) do
182171
UserWithInvalidRelation.reflect_on_association(rel).klass
183172
end
184173

185-
assert_includes err.message, expected
174+
assert_match "not an ActiveRecord::Base subclass", error.message
175+
assert_match "UserWithInvalidRelation##{rel}", error.message
186176
end
187177
end
188178

@@ -570,6 +560,11 @@ def test_reflect_on_association_accepts_strings
570560
end
571561
end
572562

563+
def test_automatic_inverse_suppresses_name_error_for_association
564+
reflection = UserWithInvalidRelation.reflect_on_association(:not_a_class)
565+
assert_not reflection.dup.has_inverse? # dup to prevent global memoization
566+
end
567+
573568
private
574569
def assert_reflection(klass, association, options)
575570
assert reflection = klass.reflect_on_association(association)

activerecord/test/models/user_with_invalid_relation.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# frozen_string_literal: true
22

33
class UserWithInvalidRelation < ActiveRecord::Base
4-
has_one :account_invalid_no_class_name_option
5-
6-
has_one :account_class_name, class_name: "AccountInvalid"
4+
has_one :not_a_class
75

86
has_one :class_name_provided_not_a_class, class_name: "NotAClass"
97

8+
has_one :account_invalid
9+
10+
has_one :account_class_name, class_name: "AccountInvalid"
11+
1012
has_many :user_info_invalid
1113
has_many :info_invalids, through: :user_info_invalid
1214

0 commit comments

Comments
 (0)