has_many_association.rb 4.0 KB
Newer Older
D
Initial  
David Heinemeier Hansson 已提交
1 2 3 4 5 6 7 8 9 10
module ActiveRecord
  module Associations
    class HasManyAssociation < AssociationCollection #:nodoc:
      def initialize(owner, association_name, association_class_name, association_class_primary_key_name, options)
        super(owner, association_name, association_class_name, association_class_primary_key_name, options)
        @conditions = @association_class.send(:sanitize_conditions, options[:conditions])

        if options[:finder_sql]
          @finder_sql = interpolate_sql(options[:finder_sql])
        else
11
          @finder_sql = "#{@association_class_primary_key_name} = #{@owner.quoted_id} #{@conditions ? " AND " + interpolate_sql(@conditions) : ""}"
12 13 14 15 16 17 18
        end

        if options[:counter_sql]
          @counter_sql = interpolate_sql(options[:counter_sql])
        elsif options[:finder_sql]
          @counter_sql = options[:counter_sql] = @finder_sql.gsub(/SELECT (.*) FROM/i, "SELECT COUNT(*) FROM")
        else
19
          @counter_sql = "#{@association_class_primary_key_name} = #{@owner.quoted_id}#{@conditions ? " AND " + interpolate_sql(@conditions) : ""}"
D
Initial  
David Heinemeier Hansson 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
        end
      end

      def create(attributes = {})
        # Can't use Base.create since the foreign key may be a protected attribute.
        record = build(attributes)
        record.save
        @collection << record if loaded?
        record
      end

      def build(attributes = {})
        record = @association_class.new(attributes)
        record[@association_class_primary_key_name] = @owner.id
        record
      end

      def find_all(runtime_conditions = nil, orderings = nil, limit = nil, joins = nil, &block)
        if block_given? || @options[:finder_sql]
          load_collection
          @collection.find_all(&block)
        else
          @association_class.find_all(
43 44
            "#{@association_class_primary_key_name} = #{@owner.quoted_id}" +
            "#{@conditions ? " AND " + @conditions : ""}#{runtime_conditions ? " AND " + @association_class.send(:sanitize_conditions, runtime_conditions) : ""}",
D
Initial  
David Heinemeier Hansson 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57
            orderings, 
            limit, 
            joins
          )
        end
      end

      def find(association_id = nil, &block)
        if block_given? || @options[:finder_sql]
          load_collection
          @collection.find(&block)
        else
          @association_class.find_on_conditions(association_id,
58
            "#{@association_class_primary_key_name} = #{@owner.quoted_id}#{@conditions ? " AND " + @conditions : ""}"
D
Initial  
David Heinemeier Hansson 已提交
59 60 61 62 63 64 65
          )
        end
      end

      # Removes all records from this association.  Returns +self+ so
      # method calls may be chained.
      def clear
66
        @association_class.update_all("#{@association_class_primary_key_name} = NULL", "#{@association_class_primary_key_name} = #{@owner.quoted_id}")
D
Initial  
David Heinemeier Hansson 已提交
67 68 69 70 71 72 73 74 75 76 77 78
        @collection = []
        self
      end

      protected
        def find_all_records
          if @options[:finder_sql]
            @association_class.find_by_sql(@finder_sql)
          else
            @association_class.find_all(@finder_sql, @options[:order] ? @options[:order] : nil)
          end
        end
79

D
Initial  
David Heinemeier Hansson 已提交
80 81 82
        def count_records
          if has_cached_counter?
            @owner.send(:read_attribute, cached_counter_attribute_name)
83
          elsif @options[:counter_sql]
D
Initial  
David Heinemeier Hansson 已提交
84 85 86 87 88
            @association_class.count_by_sql(@counter_sql)
          else
            @association_class.count(@counter_sql)
          end
        end
89

D
Initial  
David Heinemeier Hansson 已提交
90 91 92
        def has_cached_counter?
          @owner.attribute_present?(cached_counter_attribute_name)
        end
93

D
Initial  
David Heinemeier Hansson 已提交
94 95 96 97 98 99 100 101 102 103
        def cached_counter_attribute_name
          "#{@association_name}_count"
        end

        def insert_record(record)
          record.update_attribute(@association_class_primary_key_name, @owner.id)
        end

        def delete_records(records)
          ids = quoted_record_ids(records)
104 105 106 107
          @association_class.update_all(
            "#{@association_class_primary_key_name} = NULL", 
            "#{@association_class_primary_key_name} = #{@owner.quoted_id} AND #{@association_class.primary_key} IN (#{ids})"
          )
D
Initial  
David Heinemeier Hansson 已提交
108 109 110 111
        end
    end
  end
end