From 373b053dc8b99dac1abc3879a17a2bf8c30302b5 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 13 Jul 2009 16:25:33 +0100 Subject: Optimize _ids for hm:t with belongs_to source --- activerecord/lib/active_record/associations.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 10ecd068d3..1b884fd2ab 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1273,9 +1273,16 @@ module ActiveRecord if send(reflection.name).loaded? || reflection.options[:finder_sql] send(reflection.name).map(&:id) else - send(reflection.name).all(:select => "#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map(&:id) + if reflection.through_reflection && reflection.source_reflection.belongs_to? + through = reflection.through_reflection + primary_key = reflection.source_reflection.primary_key_name + send(through.name).all(:select => "DISTINCT #{through.quoted_table_name}.#{primary_key}").map(&:"#{primary_key}") + else + send(reflection.name).all(:select => "#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map(&:id) + end end end + end def collection_accessor_methods(reflection, association_proxy_class, writer = true) -- cgit v1.2.3 From 40b387580ff251e06632fbcc87c2a78c027a6b27 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 13 Jul 2009 21:59:06 +0100 Subject: Use map! instead of map for _ids --- activerecord/lib/active_record/associations.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 1b884fd2ab..419967b833 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1276,9 +1276,9 @@ module ActiveRecord if reflection.through_reflection && reflection.source_reflection.belongs_to? through = reflection.through_reflection primary_key = reflection.source_reflection.primary_key_name - send(through.name).all(:select => "DISTINCT #{through.quoted_table_name}.#{primary_key}").map(&:"#{primary_key}") + send(through.name).all(:select => "DISTINCT #{through.quoted_table_name}.#{primary_key}").map!(&:"#{primary_key}") else - send(reflection.name).all(:select => "#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map(&:id) + send(reflection.name).all(:select => "#{reflection.quoted_table_name}.#{reflection.klass.primary_key}").map!(&:id) end end end -- cgit v1.2.3 From 1c11437a32a973fa9b521c32caa7256f9772acd7 Mon Sep 17 00:00:00 2001 From: Szymon Nowak Date: Wed, 15 Jul 2009 22:22:25 +0200 Subject: Add primary_key option to belongs_to association [#765 state:committed] Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/associations.rb | 9 +++++--- .../associations/belongs_to_association.rb | 26 ++++++++++++++++++---- .../belongs_to_polymorphic_association.rb | 6 ++++- .../lib/active_record/autosave_association.rb | 3 ++- 4 files changed, 35 insertions(+), 9 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 419967b833..934beb7d39 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -963,6 +963,8 @@ module ActiveRecord # of the association with an "_id" suffix. So a class that defines a belongs_to :person association will use # "person_id" as the default :foreign_key. Similarly, belongs_to :favorite_person, :class_name => "Person" # will use a foreign key of "favorite_person_id". + # [:primary_key] + # Specify the method that returns the primary key of associated object used for the association. By default this is id. # [:dependent] # If set to :destroy, the associated object is destroyed when this object is. If set to # :delete, the associated object is deleted *without* calling its destroy method. This option should not be specified when @@ -993,6 +995,7 @@ module ActiveRecord # # Option examples: # belongs_to :firm, :foreign_key => "client_of" + # belongs_to :person, :primary_key => "name", :foreign_key => "person_name" # belongs_to :author, :class_name => "Person", :foreign_key => "author_id" # belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id", # :conditions => 'discounts > #{payments_count}' @@ -1328,14 +1331,14 @@ module ActiveRecord method_name = "belongs_to_counter_cache_after_create_for_#{reflection.name}".to_sym define_method(method_name) do association = send(reflection.name) - association.class.increment_counter(cache_column, send(reflection.primary_key_name)) unless association.nil? + association.class.increment_counter(cache_column, association.id) unless association.nil? end after_create(method_name) method_name = "belongs_to_counter_cache_before_destroy_for_#{reflection.name}".to_sym define_method(method_name) do association = send(reflection.name) - association.class.decrement_counter(cache_column, send(reflection.primary_key_name)) unless association.nil? + association.class.decrement_counter(cache_column, association.id) unless association.nil? end before_destroy(method_name) @@ -1527,7 +1530,7 @@ module ActiveRecord mattr_accessor :valid_keys_for_belongs_to_association @@valid_keys_for_belongs_to_association = [ - :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, + :class_name, :primary_key, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent, :counter_cache, :extend, :polymorphic, :readonly, :validate, :touch, :inverse_of ] diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index c88575048a..628033c87a 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -14,7 +14,7 @@ module ActiveRecord if record.nil? if counter_cache_name && !@owner.new_record? - @reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name] + @reflection.klass.decrement_counter(counter_cache_name, previous_record_id) if @owner[@reflection.primary_key_name] end @target = @owner[@reflection.primary_key_name] = nil @@ -27,7 +27,7 @@ module ActiveRecord end @target = (AssociationProxy === record ? record.target : record) - @owner[@reflection.primary_key_name] = record.id unless record.new_record? + @owner[@reflection.primary_key_name] = record_id(record) unless record.new_record? @updated = true end @@ -43,13 +43,18 @@ module ActiveRecord private def find_target - the_target = @reflection.klass.find( + find_method = if @reflection.options[:primary_key] + "find_by_#{@reflection.options[:primary_key]}" + else + "find" + end + the_target = @reflection.klass.send(find_method, @owner[@reflection.primary_key_name], :select => @reflection.options[:select], :conditions => conditions, :include => @reflection.options[:include], :readonly => @reflection.options[:readonly] - ) + ) if @owner[@reflection.primary_key_name] set_inverse_instance(the_target, @owner) the_target end @@ -63,6 +68,19 @@ module ActiveRecord def we_can_set_the_inverse_on_this?(record) @reflection.has_inverse? && @reflection.inverse_of.macro == :has_one end + + def record_id(record) + record.send(@reflection.options[:primary_key] || :id) + end + + def previous_record_id + @previous_record_id ||= if @reflection.options[:primary_key] + previous_record = @owner.send(@reflection.name) + previous_record.nil? ? nil : previous_record.id + else + @owner[@reflection.primary_key_name] + end + end end end end diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index d8146daa54..67e18d692d 100644 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -7,7 +7,7 @@ module ActiveRecord else @target = (AssociationProxy === record ? record.target : record) - @owner[@reflection.primary_key_name] = record.id + @owner[@reflection.primary_key_name] = record_id(record) @owner[@reflection.options[:foreign_type]] = record.class.base_class.name.to_s @updated = true @@ -41,6 +41,10 @@ module ActiveRecord !@owner[@reflection.primary_key_name].nil? end + def record_id(record) + record.send(@reflection.options[:primary_key] || :id) + end + def association_class @owner[@reflection.options[:foreign_type]] ? @owner[@reflection.options[:foreign_type]].constantize : nil end diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index a540570f42..c1bc8423a9 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -339,7 +339,8 @@ module ActiveRecord association.save(!autosave) if association.new_record? || autosave if association.updated? - self[reflection.primary_key_name] = association.id + association_id = association.send(reflection.options[:primary_key] || :id) + self[reflection.primary_key_name] = association_id # TODO: Removing this code doesn't seem to matter… if reflection.options[:polymorphic] self[reflection.options[:foreign_type]] = association.class.base_class.name.to_s -- cgit v1.2.3