Permalink
Browse files

Remove duplicate code from associations. [Pratik]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@9231 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent f6b12c1 commit 9bc75fd007d56d818b8620569410a20aa92c9fc5 @lifo lifo committed Apr 6, 2008
View
@@ -1,5 +1,7 @@
*SVN*
+* Remove duplicate code from associations. [Pratik]
+
* Refactor HasManyThroughAssociation to inherit from HasManyAssociation. Association callbacks and <association>_ids= now work with hm:t. #11516 [rubyruy]
* Ensure HABTM#create and HABTM#build do not load entire association. [Pratik]
@@ -3,6 +3,51 @@
module ActiveRecord
module Associations
class AssociationCollection < AssociationProxy #:nodoc:
+ def initialize(owner, reflection)
+ super
+ construct_sql
+ end
+
+ def find(*args)
+ options = args.extract_options!
+
+ # If using a custom finder_sql, scan the entire collection.
+ if @reflection.options[:finder_sql]
+ expects_array = args.first.kind_of?(Array)
+ ids = args.flatten.compact.uniq.map(&:to_i)
+
+ if ids.size == 1
+ id = ids.first
+ record = load_target.detect { |r| id == r.id }
+ expects_array ? [ record ] : record
+ else
+ load_target.select { |r| ids.include?(r.id) }
+ end
+ else
+ conditions = "#{@finder_sql}"
+ if sanitized_conditions = sanitize_sql(options[:conditions])
+ conditions << " AND (#{sanitized_conditions})"
+ end
+
+ options[:conditions] = conditions
+
+ if options[:order] && @reflection.options[:order]
+ options[:order] = "#{options[:order]}, #{@reflection.options[:order]}"
+ elsif @reflection.options[:order]
+ options[:order] = @reflection.options[:order]
+ end
+
+ # Build options specific to association
+ construct_find_options!(options)
+
+ merge_options_from_reflection!(options)
+
+ # Pass through args exactly as we received them.
+ args << options
+ @reflection.klass.find(*args)
+ end
+ end
+
def to_ary
load_target
@target.to_ary
@@ -30,10 +75,9 @@ def <<(*records)
@owner.transaction do
flatten_deeper(records).each do |record|
raise_on_type_mismatch(record)
- callback(:before_add, record)
- result &&= insert_record(record) unless @owner.new_record?
- @target << record
- callback(:after_add, record)
+ add_record_to_target_with_callbacks(record) do |r|
+ result &&= insert_record(record) unless @owner.new_record?
+ end
end
end
@@ -63,18 +107,13 @@ def sum(*args)
def delete(*records)
records = flatten_deeper(records)
records.each { |record| raise_on_type_mismatch(record) }
- records.reject! do |record|
- if record.new_record?
- callback(:before_remove, record)
- @target.delete(record)
- callback(:after_remove, record)
- end
- end
- return if records.empty?
@owner.transaction do
records.each { |record| callback(:before_remove, record) }
- delete_records(records)
+
+ old_records = records.reject {|r| r.new_record? }
+ delete_records(old_records) if old_records.any?
+
records.each do |record|
@target.delete(record)
callback(:after_remove, record)
@@ -180,6 +219,9 @@ def include?(record)
end
protected
+ def construct_find_options!(options)
+ end
+
def load_target
if !@owner.new_record? || foreign_key_present
begin
@@ -1,11 +1,6 @@
module ActiveRecord
module Associations
class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
- def initialize(owner, reflection)
- super
- construct_sql
- end
-
def create(attributes = {})
create_record(attributes) { |record| insert_record(record) }
end
@@ -14,53 +9,13 @@ def create!(attributes = {})
create_record(attributes) { |record| insert_record(record, true) }
end
- def find_first
- load_target.first
- end
-
- def find(*args)
- options = args.extract_options!
-
- # If using a custom finder_sql, scan the entire collection.
- if @reflection.options[:finder_sql]
- expects_array = args.first.kind_of?(Array)
- ids = args.flatten.compact.uniq
-
- if ids.size == 1
- id = ids.first.to_i
- record = load_target.detect { |r| id == r.id }
- expects_array ? [record] : record
- else
- load_target.select { |r| ids.include?(r.id) }
- end
- else
- conditions = "#{@finder_sql}"
-
- if sanitized_conditions = sanitize_sql(options[:conditions])
- conditions << " AND (#{sanitized_conditions})"
- end
-
- options[:conditions] = conditions
+ protected
+ def construct_find_options!(options)
options[:joins] = @join_sql
options[:readonly] = finding_with_ambiguous_select?(options[:select] || @reflection.options[:select])
-
- if options[:order] && @reflection.options[:order]
- options[:order] = "#{options[:order]}, #{@reflection.options[:order]}"
- elsif @reflection.options[:order]
- options[:order] = @reflection.options[:order]
- end
-
- merge_options_from_reflection!(options)
-
- options[:select] ||= (@reflection.options[:select] || '*')
-
- # Pass through args exactly as we received them.
- args << options
- @reflection.klass.find(*args)
+ options[:select] ||= (@reflection.options[:select] || '*')
end
- end
-
- protected
+
def count_records
load_target.size
end
@@ -1,11 +1,6 @@
module ActiveRecord
module Associations
class HasManyAssociation < AssociationCollection #:nodoc:
- def initialize(owner, reflection)
- super
- construct_sql
- end
-
# Count the number of associated records. All arguments are optional.
def count(*args)
if @reflection.options[:counter_sql]
@@ -23,42 +18,6 @@ def count(*args)
end
end
- def find(*args)
- options = args.extract_options!
-
- # If using a custom finder_sql, scan the entire collection.
- if @reflection.options[:finder_sql]
- expects_array = args.first.kind_of?(Array)
- ids = args.flatten.compact.uniq.map(&:to_i)
-
- if ids.size == 1
- id = ids.first
- record = load_target.detect { |r| id == r.id }
- expects_array ? [ record ] : record
- else
- load_target.select { |r| ids.include?(r.id) }
- end
- else
- conditions = "#{@finder_sql}"
- if sanitized_conditions = sanitize_sql(options[:conditions])
- conditions << " AND (#{sanitized_conditions})"
- end
- options[:conditions] = conditions
-
- if options[:order] && @reflection.options[:order]
- options[:order] = "#{options[:order]}, #{@reflection.options[:order]}"
- elsif @reflection.options[:order]
- options[:order] = @reflection.options[:order]
- end
-
- merge_options_from_reflection!(options)
-
- # Pass through args exactly as we received them.
- args << options
- @reflection.klass.find(*args)
- end
- end
-
protected
def count_records
count = if has_cached_counter?
@@ -2,37 +2,8 @@ module ActiveRecord
module Associations
class HasManyThroughAssociation < HasManyAssociation #:nodoc:
def initialize(owner, reflection)
- super
reflection.check_validity!
- @finder_sql = construct_conditions
- end
-
-
- def find(*args)
- options = args.extract_options!
-
- conditions = "#{@finder_sql}"
- if sanitized_conditions = sanitize_sql(options[:conditions])
- conditions << " AND (#{sanitized_conditions})"
- end
- options[:conditions] = conditions
-
- if options[:order] && @reflection.options[:order]
- options[:order] = "#{options[:order]}, #{@reflection.options[:order]}"
- elsif @reflection.options[:order]
- options[:order] = @reflection.options[:order]
- end
-
- options[:select] = construct_select(options[:select])
- options[:from] ||= construct_from
- options[:joins] = construct_joins(options[:joins])
- options[:include] = @reflection.source_reflection.options[:include] if options[:include].nil?
-
- merge_options_from_reflection!(options)
-
- # Pass through args exactly as we received them.
- args << options
- @reflection.klass.find(*args)
+ super
end
alias_method :new, :build
@@ -59,15 +30,6 @@ def size
return @target.size if loaded?
return count
end
-
- # Calculate sum using SQL, not Enumerable
- def sum(*args)
- if block_given?
- calculate(:sum, *args) { |*block_args| yield(*block_args) }
- else
- calculate(:sum, *args)
- end
- end
def count(*args)
column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args)
@@ -79,8 +41,14 @@ def count(*args)
@reflection.klass.send(:with_scope, construct_scope) { @reflection.klass.count(column_name, options) }
end
-
protected
+ def construct_find_options!(options)
+ options[:select] = construct_select(options[:select])
+ options[:from] ||= construct_from
+ options[:joins] = construct_joins(options[:joins])
+ options[:include] = @reflection.source_reflection.options[:include] if options[:include].nil?
+ end
+
def insert_record(record, force=true)
if record.new_record?
if force
@@ -101,26 +69,6 @@ def delete_records(records)
end
end
- def method_missing(method, *args)
- if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
- if block_given?
- super { |*block_args| yield(*block_args) }
- else
- super
- end
- elsif @reflection.klass.scopes.include?(method)
- @reflection.klass.scopes[method].call(self, *args)
- else
- with_scope construct_scope do
- if block_given?
- @reflection.klass.send(method, *args) { |*block_args| yield(*block_args) }
- else
- @reflection.klass.send(method, *args)
- end
- end
- end
- end
-
def find_target
@reflection.klass.find(:all,
:select => construct_select,
@@ -237,6 +185,8 @@ def construct_sql
@finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{@owner.quoted_id}"
@finder_sql << " AND (#{conditions})" if conditions
+ else
+ @finder_sql = construct_conditions
end
if @reflection.options[:counter_sql]
@@ -1,6 +1,6 @@
module ActiveRecord
module Associations
- class HasOneThroughAssociation < ActiveRecord::Associations::HasManyThroughAssociation
+ class HasOneThroughAssociation < HasManyThroughAssociation
def create_through_record(new_value) #nodoc:
klass = @reflection.through_reflection.klass

0 comments on commit 9bc75fd

Please sign in to comment.