has_many_association.rb 3.1 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1
module ActiveRecord
2
  # = Active Record Has Many Association
D
Initial  
David Heinemeier Hansson 已提交
3
  module Associations
P
Pratik Naik 已提交
4 5 6 7
    # This is the proxy that handles a has many association.
    #
    # If the association has a <tt>:through</tt> option further specialization
    # is provided by its child HasManyThroughAssociation.
D
Initial  
David Heinemeier Hansson 已提交
8 9
    class HasManyAssociation < AssociationCollection #:nodoc:
      protected
P
Pratik Naik 已提交
10 11 12
        # Returns the number of records in this collection.
        #
        # If the association has a counter cache it gets that value. Otherwise
13 14
        # it will attempt to do a count via SQL, bounded to <tt>:limit</tt> if
        # there's one.  Some configuration options like :group make it impossible
15
        # to do an SQL count, in those cases the array count will be used.
16
        #
P
Pratik Naik 已提交
17 18 19 20 21 22
        # That does not depend on whether the collection has already been loaded
        # or not. The +size+ method is the one that takes the loaded flag into
        # account and delegates to +count_records+ if needed.
        #
        # If the collection is empty the target is set to an empty array and
        # the loaded flag is set to true as well.
D
Initial  
David Heinemeier Hansson 已提交
23
        def count_records
24
          count = if has_cached_counter?
D
Initial  
David Heinemeier Hansson 已提交
25
            @owner.send(:read_attribute, cached_counter_attribute_name)
26 27
          elsif @reflection.options[:counter_sql] || @reflection.options[:finder_sql]
            @reflection.klass.count_by_sql(custom_counter_sql)
D
Initial  
David Heinemeier Hansson 已提交
28
          else
29
            @reflection.klass.count(@scope[:find].slice(:conditions, :joins, :include))
D
Initial  
David Heinemeier Hansson 已提交
30
          end
31 32 33 34 35

          # If there's nothing in the database and @target has no new records
          # we are certain the current target is an empty array. This is a
          # documented side-effect of the method that may avoid an extra SELECT.
          @target ||= [] and loaded if count == 0
36

A
Aaron Patterson 已提交
37
          [@reflection.options[:limit], count].compact.min
D
Initial  
David Heinemeier Hansson 已提交
38
        end
39

D
Initial  
David Heinemeier Hansson 已提交
40 41 42
        def has_cached_counter?
          @owner.attribute_present?(cached_counter_attribute_name)
        end
43

D
Initial  
David Heinemeier Hansson 已提交
44
        def cached_counter_attribute_name
45
          "#{@reflection.name}_count"
D
Initial  
David Heinemeier Hansson 已提交
46 47
        end

48
        def insert_record(record, force = false, validate = true)
49
          set_owner_attributes(record)
50
          save_record(record, force, validate)
D
Initial  
David Heinemeier Hansson 已提交
51 52
        end

53
        # Deletes the records according to the <tt>:dependent</tt> option.
D
Initial  
David Heinemeier Hansson 已提交
54
        def delete_records(records)
55 56
          case @reflection.options[:dependent]
            when :destroy
57
              records.each { |r| r.destroy }
58
            when :delete_all
59
              @reflection.klass.delete(records.map { |r| r.id })
60
            else
61
              updates    = { @reflection.foreign_key => nil }
62
              conditions = { @reflection.association_primary_key => records.map { |r| r.id } }
63 64 65 66

              with_scope(@scope) do
                @reflection.klass.update_all(updates, conditions)
              end
67
          end
68

69 70
          if has_cached_counter? && @reflection.options[:dependent] != :destroy
            @owner.class.update_counters(@owner.id, cached_counter_attribute_name => -records.size)
71
          end
D
Initial  
David Heinemeier Hansson 已提交
72
        end
73

74
        def construct_create_scope
75
          construct_owner_attributes
76
        end
D
Initial  
David Heinemeier Hansson 已提交
77 78 79
    end
  end
end