1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Fix has_one through reflection casting check

Fixes a bug where has_one through relations with non-integer primary
keys were incorrectly raising an implementation error even though a
reflectable association was present.
This commit is contained in:
Gannon McGibbon 2019-09-03 19:28:40 -04:00
parent 352560308b
commit d739c835bc
2 changed files with 63 additions and 9 deletions

View file

@ -766,7 +766,8 @@ module ActiveRecord
def klass def klass
@klass ||= delegate_reflection.compute_class(class_name).tap do |klass| @klass ||= delegate_reflection.compute_class(class_name).tap do |klass|
if !parent_reflection.is_a?(HasAndBelongsToManyReflection) && if !parent_reflection.is_a?(HasAndBelongsToManyReflection) &&
!klass.reflections.include?(options[:through].to_s) && !(klass.reflections.key?(options[:through].to_s) ||
klass.reflections.key?(options[:through].to_s.pluralize)) &&
active_record.type_for_attribute(active_record.primary_key).type != :integer active_record.type_for_attribute(active_record.primary_key).type != :integer
raise NotImplementedError, <<~MSG.squish raise NotImplementedError, <<~MSG.squish
In order to correctly type cast #{active_record}.#{active_record.primary_key}, In order to correctly type cast #{active_record}.#{active_record.primary_key},

View file

@ -256,14 +256,6 @@ class ReflectionTest < ActiveRecord::TestCase
assert_kind_of ThroughReflection, Subscriber.reflect_on_association(:books) assert_kind_of ThroughReflection, Subscriber.reflect_on_association(:books)
end end
def test_uncastable_has_many_through_reflection
error = assert_raises(NotImplementedError) { Subscriber.new.published_books }
assert_equal <<~MSG.squish, error.message
In order to correctly type cast Subscriber.nick,
PublishedBook needs to define a :subscriptions association.
MSG
end
def test_chain def test_chain
expected = [ expected = [
Organization.reflect_on_association(:author_essay_categories), Organization.reflect_on_association(:author_essay_categories),
@ -524,3 +516,64 @@ class ReflectionTest < ActiveRecord::TestCase
end end
end end
end end
class UncastableReflectionTest < ActiveRecord::TestCase
class Book < ActiveRecord::Base
end
class Subscription < ActiveRecord::Base
belongs_to :subscriber
belongs_to :book
end
class Subscriber < ActiveRecord::Base
self.primary_key = "nick"
has_many :subscriptions
has_one :subscription
has_many :books, through: :subscriptions
has_one :book, through: :subscription
end
setup do
@subscriber = Subscriber.create!(nick: "unique")
end
teardown do
Book._reflections.clear
Book.clear_reflections_cache
Subscriber.has_many :books, through: :subscriptions
Subscriber.has_one :book, through: :subscription
end
test "uncastable has_many through: reflection" do
error = assert_raises(NotImplementedError) { @subscriber.books }
assert_equal <<~MSG.squish, error.message
In order to correctly type cast UncastableReflectionTest::Subscriber.nick,
UncastableReflectionTest::Book needs to define a :subscriptions association.
MSG
end
test "fixing uncastable has_many through: reflection with has_many" do
Book.has_many :subscriptions
@subscriber.books
end
test "uncastable has_one through: reflection" do
error = assert_raises(NotImplementedError) { @subscriber.book }
assert_equal <<~MSG.squish, error.message
In order to correctly type cast UncastableReflectionTest::Subscriber.nick,
UncastableReflectionTest::Book needs to define a :subscription association.
MSG
end
test "fixing uncastable has_one through: reflection with has_many" do
Book.has_many :subscriptions
@subscriber.book
end
test "fixing uncastable has_one through: reflection with has_one" do
Book.has_one :subscription
@subscriber.book
end
end