mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Support has_one through assocs as the source association
This commit is contained in:
parent
7aea695815
commit
1777600e6e
7 changed files with 71 additions and 20 deletions
|
@ -53,7 +53,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def construct_joins(custom_joins = nil)
|
def construct_joins(custom_joins = nil)
|
||||||
# puts @reflection.through_reflection_chain.map(&:inspect)
|
# p @reflection.through_reflection_chain
|
||||||
|
|
||||||
"#{construct_through_joins} #{@reflection.options[:joins]} #{custom_joins}"
|
"#{construct_through_joins} #{@reflection.options[:joins]} #{custom_joins}"
|
||||||
end
|
end
|
||||||
|
@ -67,16 +67,27 @@ module ActiveRecord
|
||||||
|
|
||||||
case
|
case
|
||||||
when left.source_reflection.nil?
|
when left.source_reflection.nil?
|
||||||
left_primary_key = left.primary_key_name
|
# TODO: Perhaps need to pay attention to left.options[:primary_key] and
|
||||||
right_primary_key = right.klass.primary_key
|
# left.options[:foreign_key] in places here
|
||||||
|
|
||||||
if left.options[:as]
|
case left.macro
|
||||||
polymorphic_join = "AND %s.%s = %s" % [
|
when :belongs_to
|
||||||
table_aliases[left], "#{left.options[:as]}_type",
|
left_primary_key = left.klass.primary_key
|
||||||
# TODO: Why right.klass.name? Rather than left.active_record.name?
|
right_primary_key = right.primary_key_name
|
||||||
# TODO: Also should maybe use the base_class (see related code in JoinAssociation)
|
when :has_many, :has_one
|
||||||
@owner.class.quote_value(right.klass.name)
|
left_primary_key = left.primary_key_name
|
||||||
]
|
right_primary_key = right.klass.primary_key
|
||||||
|
|
||||||
|
if left.options[:as]
|
||||||
|
polymorphic_join = "AND %s.%s = %s" % [
|
||||||
|
table_aliases[left], "#{left.options[:as]}_type",
|
||||||
|
# TODO: Why right.klass.name? Rather than left.active_record.name?
|
||||||
|
# TODO: Also should maybe use the base_class (see related code in JoinAssociation)
|
||||||
|
@owner.class.quote_value(right.klass.name)
|
||||||
|
]
|
||||||
|
end
|
||||||
|
when :has_and_belongs_to_many
|
||||||
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
when left.source_reflection.macro == :belongs_to
|
when left.source_reflection.macro == :belongs_to
|
||||||
left_primary_key = left.klass.primary_key
|
left_primary_key = left.klass.primary_key
|
||||||
|
|
|
@ -18,6 +18,9 @@ require 'models/subscriber'
|
||||||
require 'models/book'
|
require 'models/book'
|
||||||
require 'models/subscription'
|
require 'models/subscription'
|
||||||
require 'models/rating'
|
require 'models/rating'
|
||||||
|
require 'models/member'
|
||||||
|
require 'models/member_detail'
|
||||||
|
require 'models/member_type'
|
||||||
|
|
||||||
# NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which
|
# NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which
|
||||||
# are just one level deep. But it's all the same thing really, as the "nested" code is being
|
# are just one level deep. But it's all the same thing really, as the "nested" code is being
|
||||||
|
@ -26,7 +29,8 @@ require 'models/rating'
|
||||||
|
|
||||||
class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase
|
class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase
|
||||||
fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings,
|
fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings,
|
||||||
:people, :readers, :references, :jobs, :ratings, :comments
|
:people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details,
|
||||||
|
:member_types
|
||||||
|
|
||||||
# Through associations can either use the has_many or has_one macros.
|
# Through associations can either use the has_many or has_one macros.
|
||||||
#
|
#
|
||||||
|
@ -56,6 +60,9 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase
|
||||||
authors = Author.joins(:tags).where('tags.id' => tags(:general).id)
|
authors = Author.joins(:tags).where('tags.id' => tags(:general).id)
|
||||||
assert_equal [authors(:david)], authors.uniq
|
assert_equal [authors(:david)], authors.uniq
|
||||||
|
|
||||||
|
authors = Author.includes(:tags)
|
||||||
|
assert_equal [tags(:general), tags(:general)], authors.first.tags
|
||||||
|
|
||||||
# This ensures that the polymorphism of taggings is being observed correctly
|
# This ensures that the polymorphism of taggings is being observed correctly
|
||||||
authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel')
|
authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel')
|
||||||
assert authors.empty?
|
assert authors.empty?
|
||||||
|
@ -71,11 +78,24 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase
|
||||||
# All authors with subscribers where one of the subscribers' nick is 'alterself'
|
# All authors with subscribers where one of the subscribers' nick is 'alterself'
|
||||||
authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself')
|
authors = Author.joins(:subscribers).where('subscribers.nick' => 'alterself')
|
||||||
assert_equal [authors(:david)], authors
|
assert_equal [authors(:david)], authors
|
||||||
|
|
||||||
|
# TODO: Make this work
|
||||||
|
# authors = Author.includes(:subscribers)
|
||||||
|
# assert_equal [subscribers(:first), subscribers(:second), subscribers(:second)], authors.first.subscribers
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: has_many through
|
# has_many through
|
||||||
# Source: has_one through
|
# Source: has_one through
|
||||||
# Through: has_one
|
# Through: has_one
|
||||||
|
def test_has_many_through_has_one_with_has_one_through_source_reflection
|
||||||
|
assert_equal [member_types(:founding)], members(:groucho).nested_member_types
|
||||||
|
|
||||||
|
members = Member.joins(:nested_member_types).where('member_types.id' => member_types(:founding).id)
|
||||||
|
assert_equal [members(:groucho)], members
|
||||||
|
|
||||||
|
members = Member.includes(:nested_member_types)
|
||||||
|
assert_equal [member_types(:founding)], members.first.nested_member_types
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: has_many through
|
# TODO: has_many through
|
||||||
# Source: has_one
|
# Source: has_one
|
||||||
|
@ -105,9 +125,18 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase
|
||||||
# Source: has_many through
|
# Source: has_many through
|
||||||
# Through: belongs_to
|
# Through: belongs_to
|
||||||
|
|
||||||
# TODO: has_one through
|
# has_one through
|
||||||
# Source: has_one through
|
# Source: has_one through
|
||||||
# Through: has_one
|
# Through: has_one
|
||||||
|
def test_has_one_through_has_one_with_has_one_through_source_reflection
|
||||||
|
assert_equal member_types(:founding), members(:groucho).nested_member_type
|
||||||
|
|
||||||
|
members = Member.joins(:nested_member_type).where('member_types.id' => member_types(:founding).id)
|
||||||
|
assert_equal [members(:groucho)], members
|
||||||
|
|
||||||
|
members = Member.includes(:nested_member_type)
|
||||||
|
assert_equal member_types(:founding), members.first.nested_member_type
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: has_one through
|
# TODO: has_one through
|
||||||
# Source: belongs_to
|
# Source: belongs_to
|
||||||
|
|
3
activerecord/test/fixtures/member_details.yml
vendored
Normal file
3
activerecord/test/fixtures/member_details.yml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
groucho:
|
||||||
|
id: 1
|
||||||
|
member_id: 1
|
2
activerecord/test/fixtures/members.yml
vendored
2
activerecord/test/fixtures/members.yml
vendored
|
@ -1,6 +1,8 @@
|
||||||
groucho:
|
groucho:
|
||||||
|
id: 1
|
||||||
name: Groucho Marx
|
name: Groucho Marx
|
||||||
member_type_id: 1
|
member_type_id: 1
|
||||||
some_other_guy:
|
some_other_guy:
|
||||||
|
id: 2
|
||||||
name: Englebert Humperdink
|
name: Englebert Humperdink
|
||||||
member_type_id: 2
|
member_type_id: 2
|
||||||
|
|
6
activerecord/test/fixtures/memberships.yml
vendored
6
activerecord/test/fixtures/memberships.yml
vendored
|
@ -1,20 +1,20 @@
|
||||||
membership_of_boring_club:
|
membership_of_boring_club:
|
||||||
joined_on: <%= 3.weeks.ago.to_s(:db) %>
|
joined_on: <%= 3.weeks.ago.to_s(:db) %>
|
||||||
club: boring_club
|
club: boring_club
|
||||||
member: groucho
|
member_id: 1
|
||||||
favourite: false
|
favourite: false
|
||||||
type: CurrentMembership
|
type: CurrentMembership
|
||||||
|
|
||||||
membership_of_favourite_club:
|
membership_of_favourite_club:
|
||||||
joined_on: <%= 3.weeks.ago.to_s(:db) %>
|
joined_on: <%= 3.weeks.ago.to_s(:db) %>
|
||||||
club: moustache_club
|
club: moustache_club
|
||||||
member: groucho
|
member_id: 1
|
||||||
favourite: true
|
favourite: true
|
||||||
type: Membership
|
type: Membership
|
||||||
|
|
||||||
other_guys_membership:
|
other_guys_membership:
|
||||||
joined_on: <%= 4.weeks.ago.to_s(:db) %>
|
joined_on: <%= 4.weeks.ago.to_s(:db) %>
|
||||||
club: boring_club
|
club: boring_club
|
||||||
member: some_other_guy
|
member_id: 2
|
||||||
favourite: false
|
favourite: false
|
||||||
type: CurrentMembership
|
type: CurrentMembership
|
||||||
|
|
9
activerecord/test/fixtures/sponsors.yml
vendored
9
activerecord/test/fixtures/sponsors.yml
vendored
|
@ -1,9 +1,12 @@
|
||||||
moustache_club_sponsor_for_groucho:
|
moustache_club_sponsor_for_groucho:
|
||||||
sponsor_club: moustache_club
|
sponsor_club: moustache_club
|
||||||
sponsorable: groucho (Member)
|
sponsorable_id: 1
|
||||||
|
sponsorable_type: Member
|
||||||
boring_club_sponsor_for_groucho:
|
boring_club_sponsor_for_groucho:
|
||||||
sponsor_club: boring_club
|
sponsor_club: boring_club
|
||||||
sponsorable: some_other_guy (Member)
|
sponsorable_id: 2
|
||||||
|
sponsorable_type: Member
|
||||||
crazy_club_sponsor_for_groucho:
|
crazy_club_sponsor_for_groucho:
|
||||||
sponsor_club: crazy_club
|
sponsor_club: crazy_club
|
||||||
sponsorable: some_other_guy (Member)
|
sponsorable_id: 2
|
||||||
|
sponsorable_type: Member
|
||||||
|
|
|
@ -9,4 +9,7 @@ class Member < ActiveRecord::Base
|
||||||
has_one :member_detail
|
has_one :member_detail
|
||||||
has_one :organization, :through => :member_detail
|
has_one :organization, :through => :member_detail
|
||||||
belongs_to :member_type
|
belongs_to :member_type
|
||||||
end
|
|
||||||
|
has_many :nested_member_types, :through => :member_detail, :source => :member_type
|
||||||
|
has_one :nested_member_type, :through => :member_detail, :source => :member_type
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in a new issue