Ticket #7143: golden.diff
| File golden.diff, 14.8 kB (added by protocool, 3 years ago) |
|---|
-
activerecord/test/associations/join_model_test.rb
old new 298 298 assert_equal [posts(:welcome), posts(:thinking)], tags(:general).taggings.find(:all, :include => :taggable) 299 299 end 300 300 end 301 302 def test_has_many_polymorphic_with_source_type 303 assert_equal [posts(:welcome), posts(:thinking)], tags(:general).tagged_posts 304 end 301 305 306 def test_eager_has_many_polymorphic_with_source_type 307 tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts) 308 desired = [posts(:welcome), posts(:thinking)] 309 assert_no_queries do 310 assert_equal desired, tag_with_include.tagged_posts 311 end 312 end 313 302 314 def test_has_many_through_has_many_find_all 303 315 assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first 304 316 end -
activerecord/test/fixtures/tag.rb
old new 2 2 has_many :taggings 3 3 has_many :taggables, :through => :taggings 4 4 has_one :tagging 5 6 has_many :tagged_posts, :through => :taggings, :source => :taggable, :source_type => 'Post' 5 7 end -
activerecord/lib/active_record/reflection.rb
old new 178 178 if source_reflection.nil? 179 179 raise HasManyThroughSourceAssociationNotFoundError.new(self) 180 180 end 181 182 if options[:source_type] && source_reflection.options[:polymorphic].nil? 183 raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection) 184 end 181 185 182 if source_reflection.options[:polymorphic] 186 if source_reflection.options[:polymorphic] && options[:source_type].nil? 183 187 raise HasManyThroughAssociationPolymorphicError.new(active_record.name, self, source_reflection) 184 188 end 185 189 … … 193 197 def derive_class_name 194 198 # get the class_name of the belongs_to association of the through reflection 195 199 if through_reflection 196 source_reflection.class_name200 options[:source_type] || source_reflection.class_name 197 201 else 198 202 class_name = name.to_s.camelize 199 203 class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro) -
activerecord/lib/active_record/associations/has_many_through_association.rb
old new 138 138 139 139 # Construct attributes for :through pointing to owner and associate. 140 140 def construct_join_attributes(associate) 141 construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.association_foreign_key => associate.id) 141 returning construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.association_foreign_key => associate.id) do |join_attributes| 142 if @reflection.options[:source_type] 143 join_attributes.merge!(@reflection.source_reflection.options[:foreign_type] => associate.class.base_class.name.to_s) 144 end 145 end 142 146 end 143 147 144 148 # Associate attributes pointing to owner, quoted. … … 176 180 if @reflection.through_reflection.options[:as] || @reflection.source_reflection.macro == :belongs_to 177 181 reflection_primary_key = @reflection.klass.primary_key 178 182 source_primary_key = @reflection.source_reflection.primary_key_name 183 if @reflection.options[:source_type] 184 polymorphic_join = "AND %s.%s = %s" % [ 185 @reflection.through_reflection.table_name, "#{@reflection.source_reflection.options[:foreign_type]}", 186 @owner.class.quote_value(@reflection.options[:source_type]) 187 ] 188 end 179 189 else 180 190 reflection_primary_key = @reflection.source_reflection.primary_key_name 181 191 source_primary_key = @reflection.klass.primary_key -
activerecord/lib/active_record/associations.rb
old new 20 20 super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}'.") 21 21 end 22 22 end 23 23 24 class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc: 25 def initialize(owner_class_name, reflection, source_reflection) 26 super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.") 27 end 28 end 29 24 30 class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc: 25 31 def initialize(reflection) 26 32 through_reflection = reflection.through_reflection … … 593 599 # * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be 594 600 # inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either +:subscribers+ or 595 601 # +:subscriber+ on +Subscription+, unless a +:source+ is given. 602 # * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source association 603 # is a polymorphic belongs_to. 596 604 # * <tt>:uniq</tt> - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through. 597 605 # 598 606 # Option examples: … … 1151 1159 :class_name, :table_name, :foreign_key, 1152 1160 :exclusively_dependent, :dependent, 1153 1161 :select, :conditions, :include, :order, :group, :limit, :offset, 1154 :as, :through, :source, 1162 :as, :through, :source, :source_type, 1155 1163 :uniq, 1156 1164 :finder_sql, :counter_sql, 1157 1165 :before_add, :after_add, :before_remove, :after_remove, … … 1555 1563 case 1556 1564 when reflection.macro == :has_many && reflection.options[:through] 1557 1565 through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : '' 1566 1567 jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil 1568 first_key = second_key = as_extra = nil 1569 1558 1570 if through_reflection.options[:as] # has_many :through against a polymorphic join 1559 polymorphic_foreign_key = through_reflection.options[:as].to_s + '_id' 1560 polymorphic_foreign_type = through_reflection.options[:as].to_s + '_type' 1561 1562 " LEFT OUTER JOIN %s ON (%s.%s = %s.%s AND %s.%s = %s) " % [ 1563 table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), 1564 aliased_join_table_name, polymorphic_foreign_key, 1565 parent.aliased_table_name, parent.primary_key, 1566 aliased_join_table_name, polymorphic_foreign_type, klass.quote_value(parent.active_record.base_class.name)] + 1567 " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [table_name_and_alias, 1568 aliased_table_name, primary_key, aliased_join_table_name, options[:foreign_key] || reflection.klass.to_s.classify.foreign_key 1571 jt_foreign_key = through_reflection.options[:as].to_s + '_id' 1572 jt_as_extra = " AND %s.%s = %s" % [ 1573 aliased_join_table_name, reflection.active_record.connection.quote_column_name(through_reflection.options[:as].to_s + '_type'), 1574 klass.quote_value(parent.active_record.base_class.name) 1569 1575 ] 1570 1576 else 1571 if source_reflection.macro == :has_many && source_reflection.options[:as]1572 " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [1573 table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), aliased_join_table_name,1574 through_reflection.primary_key_name,1575 parent.aliased_table_name, parent.primary_key] +1576 " LEFT OUTER JOIN %s ON %s.%s = %s.%s AND %s.%s = %s " % [1577 table_name_and_alias,1578 aliased_table_name, "#{source_reflection.options[:as]}_id",1579 aliased_join_table_name, options[:foreign_key] || primary_key,1580 aliased_table_name, "#{source_reflection.options[:as]}_type",1577 jt_foreign_key = through_reflection.primary_key_name 1578 end 1579 1580 case source_reflection.macro 1581 when :has_many 1582 if source_reflection.options[:as] 1583 first_key = "#{source_reflection.options[:as]}_id" 1584 second_key = options[:foreign_key] || primary_key 1585 as_extra = " AND %s.%s = %s" % [ 1586 aliased_table_name, reflection.active_record.connection.quote_column_name("#{source_reflection.options[:as]}_type"), 1581 1587 klass.quote_value(source_reflection.active_record.base_class.name) 1582 1588 ] 1583 1589 else 1584 case source_reflection.macro 1585 when :belongs_to 1586 first_key = primary_key 1587 second_key = source_reflection.options[:foreign_key] || klass.to_s.classify.foreign_key 1588 extra = nil 1589 when :has_many 1590 first_key = through_reflection.klass.base_class.to_s.classify.foreign_key 1591 second_key = options[:foreign_key] || primary_key 1592 extra = through_reflection.klass.descends_from_active_record? ? nil : 1593 " AND %s.%s = %s" % [ 1594 aliased_join_table_name, 1595 reflection.active_record.connection.quote_column_name(through_reflection.active_record.inheritance_column), 1596 through_reflection.klass.quote_value(through_reflection.klass.name.demodulize)] 1597 end 1598 " LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s) " % [ 1599 table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), 1600 aliased_join_table_name, through_reflection.primary_key_name, 1601 parent.aliased_table_name, parent.primary_key, extra] + 1602 " LEFT OUTER JOIN %s ON (%s.%s = %s.%s) " % [ 1603 table_name_and_alias, 1604 aliased_table_name, first_key, 1605 aliased_join_table_name, second_key 1590 first_key = through_reflection.klass.base_class.to_s.classify.foreign_key 1591 second_key = options[:foreign_key] || primary_key 1592 end 1593 1594 unless through_reflection.klass.descends_from_active_record? 1595 jt_sti_extra = " AND %s.%s = %s" % [ 1596 aliased_join_table_name, 1597 reflection.active_record.connection.quote_column_name(through_reflection.active_record.inheritance_column), 1598 through_reflection.klass.quote_value(through_reflection.klass.name.demodulize)] 1599 end 1600 when :belongs_to 1601 first_key = primary_key 1602 if reflection.options[:source_type] 1603 second_key = source_reflection.association_foreign_key 1604 jt_source_extra = " AND %s.%s = %s" % [ 1605 aliased_join_table_name, reflection.active_record.connection.quote_column_name(reflection.source_reflection.options[:foreign_type]), 1606 klass.quote_value(reflection.options[:source_type]) 1606 1607 ] 1608 else 1609 second_key = source_reflection.options[:foreign_key] || klass.to_s.classify.foreign_key 1607 1610 end 1608 1611 end 1612 1613 " LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s%s%s) " % [ 1614 table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), 1615 parent.aliased_table_name, reflection.active_record.connection.quote_column_name(parent.primary_key), 1616 aliased_join_table_name, reflection.active_record.connection.quote_column_name(jt_foreign_key), 1617 jt_as_extra, jt_source_extra, jt_sti_extra 1618 ] + 1619 " LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s) " % [ 1620 table_name_and_alias, 1621 aliased_table_name, reflection.active_record.connection.quote_column_name(first_key), 1622 aliased_join_table_name, reflection.active_record.connection.quote_column_name(second_key), 1623 as_extra 1624 ] 1609 1625 1610 1626 when reflection.macro == :has_many && reflection.options[:as] 1611 1627 " LEFT OUTER JOIN %s ON %s.%s = %s.%s AND %s.%s = %s" % [ … … 1652 1668 end 1653 1669 1654 1670 protected 1671 1655 1672 def pluralize(table_name) 1656 1673 ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name 1657 1674 end