mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
First bit of support for habtm in through assocs - test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection now passes
This commit is contained in:
parent
199db8c8c0
commit
781ad0f8fe
6 changed files with 84 additions and 30 deletions
|
@ -2180,6 +2180,7 @@ module ActiveRecord
|
|||
# to represent the join table)
|
||||
table, join_table = table
|
||||
|
||||
# TODO: Can join_key just be reflection.primary_key_name ?
|
||||
join_key = reflection.options[:foreign_key] ||
|
||||
reflection.active_record.to_s.foreign_key
|
||||
join_foreign_key = reflection.active_record.primary_key
|
||||
|
@ -2192,18 +2193,37 @@ module ActiveRecord
|
|||
# We've done the first join now, so update the foreign_table for the second
|
||||
foreign_table = join_table
|
||||
|
||||
# TODO: Can foreign_key be reflection.association_foreign_key?
|
||||
key = reflection.klass.primary_key
|
||||
foreign_key = reflection.options[:association_foreign_key] ||
|
||||
reflection.klass.to_s.foreign_key
|
||||
end
|
||||
elsif reflection.source_reflection.macro == :belongs_to
|
||||
key = reflection.klass.primary_key
|
||||
foreign_key = reflection.source_reflection.primary_key_name
|
||||
|
||||
conditions << source_type_conditions(reflection, foreign_table)
|
||||
else
|
||||
key = reflection.source_reflection.primary_key_name
|
||||
foreign_key = reflection.source_reflection.klass.primary_key
|
||||
case reflection.source_reflection.macro
|
||||
when :belongs_to
|
||||
key = reflection.klass.primary_key
|
||||
foreign_key = reflection.source_reflection.primary_key_name
|
||||
|
||||
conditions << source_type_conditions(reflection, foreign_table)
|
||||
when :has_many, :has_one
|
||||
key = reflection.source_reflection.primary_key_name
|
||||
foreign_key = reflection.source_reflection.klass.primary_key
|
||||
when :has_and_belongs_to_many
|
||||
table, join_table = table
|
||||
|
||||
join_key = reflection.source_reflection.primary_key_name
|
||||
join_foreign_key = reflection.source_reflection.klass.primary_key
|
||||
|
||||
relation = relation.join(join_table, join_type).on(
|
||||
join_table[join_key].
|
||||
eq(foreign_table[join_foreign_key])
|
||||
)
|
||||
|
||||
foreign_table = join_table
|
||||
|
||||
key = reflection.klass.primary_key
|
||||
foreign_key = reflection.source_reflection.association_foreign_key
|
||||
end
|
||||
end
|
||||
|
||||
conditions << table[key].eq(foreign_table[foreign_key])
|
||||
|
@ -2269,14 +2289,19 @@ module ActiveRecord
|
|||
|
||||
# For habtm, we have two Arel::Table instances related to a single reflection, so
|
||||
# we just store them as a pair in the array.
|
||||
if reflection.macro == :has_and_belongs_to_many
|
||||
if reflection.macro == :has_and_belongs_to_many ||
|
||||
(reflection.source_reflection &&
|
||||
reflection.source_reflection.macro == :has_and_belongs_to_many)
|
||||
|
||||
join_table_name = (reflection.source_reflection || reflection).options[:join_table]
|
||||
|
||||
aliased_join_table_name = alias_tracker.aliased_name_for(
|
||||
reflection.options[:join_table],
|
||||
join_table_name,
|
||||
table_alias_for(reflection, true)
|
||||
)
|
||||
|
||||
join_table = Arel::Table.new(
|
||||
reflection.options[:join_table], :engine => arel_engine,
|
||||
join_table_name, :engine => arel_engine,
|
||||
:as => aliased_join_table_name
|
||||
)
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ module ActiveRecord
|
|||
# Iterate over each pair in the through reflection chain, joining them together
|
||||
@reflection.through_reflection_chain.each_cons(2) do |left, right|
|
||||
polymorphic_join = nil
|
||||
left_table, right_table = table_aliases[left], table_aliases[right]
|
||||
|
||||
if left.source_reflection.nil?
|
||||
# TODO: Perhaps need to pay attention to left.options[:primary_key] and
|
||||
|
@ -114,20 +115,31 @@ module ActiveRecord
|
|||
]
|
||||
end
|
||||
when :has_and_belongs_to_many
|
||||
raise NotImplementedError
|
||||
join_table, left_table = left_table
|
||||
|
||||
left_primary_key = left.klass.primary_key
|
||||
join_primary_key = left.source_reflection.association_foreign_key
|
||||
|
||||
joins << "INNER JOIN %s ON %s.%s = %s.%s" % [
|
||||
table_name_and_alias(
|
||||
quote_table_name(left.source_reflection.options[:join_table]),
|
||||
join_table
|
||||
),
|
||||
left_table, left_primary_key,
|
||||
join_table, join_primary_key
|
||||
]
|
||||
|
||||
left_table = join_table
|
||||
|
||||
left_primary_key = left.source_reflection.primary_key_name
|
||||
right_primary_key = right.klass.primary_key
|
||||
end
|
||||
end
|
||||
|
||||
if right.quoted_table_name == table_aliases[right]
|
||||
table = right.quoted_table_name
|
||||
else
|
||||
table = "#{right.quoted_table_name} #{table_aliases[right]}"
|
||||
end
|
||||
|
||||
joins << "INNER JOIN %s ON %s.%s = %s.%s %s" % [
|
||||
table,
|
||||
table_aliases[left], left_primary_key,
|
||||
table_aliases[right], right_primary_key,
|
||||
table_name_and_alias(right.quoted_table_name, right_table),
|
||||
left_table, left_primary_key,
|
||||
right_table, right_primary_key,
|
||||
polymorphic_join
|
||||
]
|
||||
end
|
||||
|
@ -147,13 +159,16 @@ module ActiveRecord
|
|||
table_alias_for(reflection, reflection != @reflection)
|
||||
))
|
||||
|
||||
if reflection.macro == :has_and_belongs_to_many
|
||||
if reflection.macro == :has_and_belongs_to_many ||
|
||||
(reflection.source_reflection &&
|
||||
reflection.source_reflection.macro == :has_and_belongs_to_many)
|
||||
|
||||
join_table_alias = quote_table_name(alias_tracker.aliased_name_for(
|
||||
reflection.options[:join_table],
|
||||
(reflection.source_reflection || reflection).options[:join_table],
|
||||
table_alias_for(reflection, true)
|
||||
))
|
||||
|
||||
aliases[reflection] = [table_alias, join_table_alias]
|
||||
aliases[reflection] = [join_table_alias, table_alias]
|
||||
else
|
||||
aliases[reflection] = table_alias
|
||||
end
|
||||
|
@ -173,6 +188,10 @@ module ActiveRecord
|
|||
def quote_table_name(table_name)
|
||||
@reflection.klass.connection.quote_table_name(table_name)
|
||||
end
|
||||
|
||||
def table_name_and_alias(table_name, table_alias)
|
||||
"#{table_name} #{table_alias if table_alias != table_name}".strip
|
||||
end
|
||||
|
||||
# Construct attributes for associate pointing to owner.
|
||||
def construct_owner_attributes(reflection)
|
||||
|
|
|
@ -719,7 +719,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
|
|||
|
||||
def test_find_scoped_grouped
|
||||
assert_equal 5, categories(:general).posts_grouped_by_title.size
|
||||
assert_equal 2, categories(:technology).posts_grouped_by_title.size
|
||||
assert_equal 1, categories(:technology).posts_grouped_by_title.size
|
||||
end
|
||||
|
||||
def test_find_scoped_grouped_having
|
||||
|
|
|
@ -159,10 +159,15 @@ class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase
|
|||
# has_many through
|
||||
# Source: has_and_belongs_to_many
|
||||
# Through: has_many
|
||||
# TODO: Enable and implement this, and finish off the test
|
||||
# def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection
|
||||
# assert_equal [categories(:general), categories(:technology)], authors(:bob).post_categories
|
||||
# end
|
||||
def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection
|
||||
assert_equal [categories(:general), categories(:cooking)], authors(:bob).post_categories
|
||||
|
||||
authors = Author.joins(:post_categories).where('categories.id' => categories(:cooking).id)
|
||||
assert_equal [authors(:bob)], authors
|
||||
|
||||
authors = Author.includes(:post_categories)
|
||||
assert_equal [categories(:general), categories(:cooking)], authors[2].post_categories
|
||||
end
|
||||
|
||||
# TODO: has_many through
|
||||
# Source: has_many
|
||||
|
|
5
activerecord/test/fixtures/categories.yml
vendored
5
activerecord/test/fixtures/categories.yml
vendored
|
@ -12,3 +12,8 @@ sti_test:
|
|||
id: 3
|
||||
name: Special category
|
||||
type: SpecialCategory
|
||||
|
||||
cooking:
|
||||
id: 4
|
||||
name: Cooking
|
||||
type: Category
|
||||
|
|
|
@ -26,6 +26,6 @@ general_misc_by_bob:
|
|||
category_id: 1
|
||||
post_id: 8
|
||||
|
||||
technology_misc_by_bob:
|
||||
category_id: 2
|
||||
cooking_misc_by_bob:
|
||||
category_id: 4
|
||||
post_id: 8
|
||||
|
|
Loading…
Reference in a new issue