activerecord 3.0.20 → 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (122) hide show
  1. data/CHANGELOG +220 -91
  2. data/README.rdoc +3 -3
  3. data/examples/performance.rb +88 -109
  4. data/lib/active_record.rb +6 -2
  5. data/lib/active_record/aggregations.rb +22 -45
  6. data/lib/active_record/associations.rb +264 -991
  7. data/lib/active_record/associations/alias_tracker.rb +85 -0
  8. data/lib/active_record/associations/association.rb +231 -0
  9. data/lib/active_record/associations/association_scope.rb +120 -0
  10. data/lib/active_record/associations/belongs_to_association.rb +40 -60
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +15 -63
  12. data/lib/active_record/associations/builder/association.rb +53 -0
  13. data/lib/active_record/associations/builder/belongs_to.rb +85 -0
  14. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +63 -0
  16. data/lib/active_record/associations/builder/has_many.rb +65 -0
  17. data/lib/active_record/associations/builder/has_one.rb +63 -0
  18. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  19. data/lib/active_record/associations/collection_association.rb +524 -0
  20. data/lib/active_record/associations/collection_proxy.rb +125 -0
  21. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +27 -118
  22. data/lib/active_record/associations/has_many_association.rb +50 -79
  23. data/lib/active_record/associations/has_many_through_association.rb +98 -67
  24. data/lib/active_record/associations/has_one_association.rb +45 -115
  25. data/lib/active_record/associations/has_one_through_association.rb +21 -25
  26. data/lib/active_record/associations/join_dependency.rb +215 -0
  27. data/lib/active_record/associations/join_dependency/join_association.rb +150 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_helper.rb +56 -0
  31. data/lib/active_record/associations/preloader.rb +177 -0
  32. data/lib/active_record/associations/preloader/association.rb +126 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  42. data/lib/active_record/associations/singular_association.rb +55 -0
  43. data/lib/active_record/associations/through_association.rb +80 -0
  44. data/lib/active_record/attribute_methods.rb +19 -5
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +9 -8
  46. data/lib/active_record/attribute_methods/dirty.rb +8 -2
  47. data/lib/active_record/attribute_methods/primary_key.rb +33 -13
  48. data/lib/active_record/attribute_methods/read.rb +17 -17
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -4
  50. data/lib/active_record/attribute_methods/write.rb +2 -1
  51. data/lib/active_record/autosave_association.rb +66 -45
  52. data/lib/active_record/base.rb +445 -273
  53. data/lib/active_record/callbacks.rb +24 -33
  54. data/lib/active_record/coders/yaml_column.rb +41 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +106 -13
  56. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +16 -2
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -12
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +16 -16
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +61 -22
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +16 -273
  62. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -42
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +44 -25
  64. data/lib/active_record/connection_adapters/column.rb +268 -0
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +686 -0
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +331 -88
  67. data/lib/active_record/connection_adapters/postgresql_adapter.rb +295 -267
  68. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -7
  69. data/lib/active_record/connection_adapters/sqlite_adapter.rb +108 -26
  70. data/lib/active_record/counter_cache.rb +7 -4
  71. data/lib/active_record/fixtures.rb +174 -192
  72. data/lib/active_record/identity_map.rb +131 -0
  73. data/lib/active_record/locking/optimistic.rb +20 -14
  74. data/lib/active_record/locking/pessimistic.rb +4 -4
  75. data/lib/active_record/log_subscriber.rb +24 -4
  76. data/lib/active_record/migration.rb +265 -144
  77. data/lib/active_record/migration/command_recorder.rb +103 -0
  78. data/lib/active_record/named_scope.rb +68 -25
  79. data/lib/active_record/nested_attributes.rb +58 -15
  80. data/lib/active_record/observer.rb +3 -7
  81. data/lib/active_record/persistence.rb +58 -38
  82. data/lib/active_record/query_cache.rb +25 -3
  83. data/lib/active_record/railtie.rb +21 -12
  84. data/lib/active_record/railties/console_sandbox.rb +6 -0
  85. data/lib/active_record/railties/databases.rake +147 -116
  86. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  87. data/lib/active_record/reflection.rb +176 -44
  88. data/lib/active_record/relation.rb +125 -49
  89. data/lib/active_record/relation/batches.rb +7 -5
  90. data/lib/active_record/relation/calculations.rb +50 -18
  91. data/lib/active_record/relation/finder_methods.rb +47 -26
  92. data/lib/active_record/relation/predicate_builder.rb +24 -21
  93. data/lib/active_record/relation/query_methods.rb +117 -101
  94. data/lib/active_record/relation/spawn_methods.rb +27 -20
  95. data/lib/active_record/result.rb +34 -0
  96. data/lib/active_record/schema.rb +5 -6
  97. data/lib/active_record/schema_dumper.rb +11 -13
  98. data/lib/active_record/serialization.rb +2 -2
  99. data/lib/active_record/serializers/xml_serializer.rb +10 -10
  100. data/lib/active_record/session_store.rb +8 -2
  101. data/lib/active_record/test_case.rb +9 -20
  102. data/lib/active_record/timestamp.rb +21 -9
  103. data/lib/active_record/transactions.rb +16 -15
  104. data/lib/active_record/validations.rb +21 -22
  105. data/lib/active_record/validations/associated.rb +3 -1
  106. data/lib/active_record/validations/uniqueness.rb +48 -58
  107. data/lib/active_record/version.rb +3 -3
  108. data/lib/rails/generators/active_record.rb +6 -0
  109. data/lib/rails/generators/active_record/migration/templates/migration.rb +10 -2
  110. data/lib/rails/generators/active_record/model/model_generator.rb +2 -1
  111. data/lib/rails/generators/active_record/model/templates/migration.rb +6 -5
  112. data/lib/rails/generators/active_record/model/templates/model.rb +2 -0
  113. data/lib/rails/generators/active_record/model/templates/module.rb +2 -0
  114. data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
  115. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +2 -1
  116. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +2 -2
  117. metadata +106 -77
  118. checksums.yaml +0 -7
  119. data/lib/active_record/association_preload.rb +0 -431
  120. data/lib/active_record/associations/association_collection.rb +0 -572
  121. data/lib/active_record/associations/association_proxy.rb +0 -304
  122. data/lib/active_record/associations/through_association_scope.rb +0 -160
@@ -0,0 +1,125 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ # Association proxies in Active Record are middlemen between the object that
4
+ # holds the association, known as the <tt>@owner</tt>, and the actual associated
5
+ # object, known as the <tt>@target</tt>. The kind of association any proxy is
6
+ # about is available in <tt>@reflection</tt>. That's an instance of the class
7
+ # ActiveRecord::Reflection::AssociationReflection.
8
+ #
9
+ # For example, given
10
+ #
11
+ # class Blog < ActiveRecord::Base
12
+ # has_many :posts
13
+ # end
14
+ #
15
+ # blog = Blog.find(:first)
16
+ #
17
+ # the association proxy in <tt>blog.posts</tt> has the object in +blog+ as
18
+ # <tt>@owner</tt>, the collection of its posts as <tt>@target</tt>, and
19
+ # the <tt>@reflection</tt> object represents a <tt>:has_many</tt> macro.
20
+ #
21
+ # This class has most of the basic instance methods removed, and delegates
22
+ # unknown methods to <tt>@target</tt> via <tt>method_missing</tt>. As a
23
+ # corner case, it even removes the +class+ method and that's why you get
24
+ #
25
+ # blog.posts.class # => Array
26
+ #
27
+ # though the object behind <tt>blog.posts</tt> is not an Array, but an
28
+ # ActiveRecord::Associations::HasManyAssociation.
29
+ #
30
+ # The <tt>@target</tt> object is not \loaded until needed. For example,
31
+ #
32
+ # blog.posts.count
33
+ #
34
+ # is computed directly through SQL and does not trigger by itself the
35
+ # instantiation of the actual post records.
36
+ class CollectionProxy # :nodoc:
37
+ alias :proxy_extend :extend
38
+
39
+ instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to|proxy_/ }
40
+
41
+ delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from,
42
+ :lock, :readonly, :having, :to => :scoped
43
+
44
+ delegate :target, :load_target, :loaded?, :scoped,
45
+ :to => :@association
46
+
47
+ delegate :select, :find, :first, :last,
48
+ :build, :create, :create!,
49
+ :concat, :delete_all, :destroy_all, :delete, :destroy, :uniq,
50
+ :sum, :count, :size, :length, :empty?,
51
+ :any?, :many?, :include?,
52
+ :to => :@association
53
+
54
+ def initialize(association)
55
+ @association = association
56
+ Array.wrap(association.options[:extend]).each { |ext| proxy_extend(ext) }
57
+ end
58
+
59
+ def respond_to?(*args)
60
+ super ||
61
+ (load_target && target.respond_to?(*args)) ||
62
+ @association.klass.respond_to?(*args)
63
+ end
64
+
65
+ def method_missing(method, *args, &block)
66
+ match = DynamicFinderMatch.match(method)
67
+ if match && match.creator?
68
+ attributes = match.attribute_names
69
+ return send(:"find_by_#{attributes.join('_and_')}", *args) || create(Hash[attributes.zip(args)])
70
+ end
71
+
72
+ if target.respond_to?(method) || (!@association.klass.respond_to?(method) && Class.respond_to?(method))
73
+ if load_target
74
+ if target.respond_to?(method)
75
+ target.send(method, *args, &block)
76
+ else
77
+ begin
78
+ super
79
+ rescue NoMethodError => e
80
+ raise e, e.message.sub(/ for #<.*$/, " via proxy for #{target}")
81
+ end
82
+ end
83
+ end
84
+
85
+ else
86
+ scoped.readonly(nil).send(method, *args, &block)
87
+ end
88
+ end
89
+
90
+ # Forwards <tt>===</tt> explicitly to the \target because the instance method
91
+ # removal above doesn't catch it. Loads the \target if needed.
92
+ def ===(other)
93
+ other === load_target
94
+ end
95
+
96
+ def to_ary
97
+ load_target.dup
98
+ end
99
+ alias_method :to_a, :to_ary
100
+
101
+ def <<(*records)
102
+ @association.concat(records) && self
103
+ end
104
+ alias_method :push, :<<
105
+
106
+ def clear
107
+ delete_all
108
+ self
109
+ end
110
+
111
+ def reload
112
+ @association.reload
113
+ self
114
+ end
115
+
116
+ def new(*args, &block)
117
+ if @association.is_a?(HasManyThroughAssociation)
118
+ @association.build(*args, &block)
119
+ else
120
+ method_missing(:new, *args, &block)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -1,142 +1,51 @@
1
- require 'active_support/deprecation'
2
-
3
1
  module ActiveRecord
4
2
  # = Active Record Has And Belongs To Many Association
5
3
  module Associations
6
- class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
4
+ class HasAndBelongsToManyAssociation < CollectionAssociation #:nodoc:
5
+ attr_reader :join_table
6
+
7
7
  def initialize(owner, reflection)
8
+ @join_table = Arel::Table.new(reflection.options[:join_table])
8
9
  super
9
- if columns.size > 2
10
- ActiveSupport::Deprecation.warn "Having additional attributes on the join table of a has_and_belongs_to_many association is deprecated and will be removed in Rails 3.1. Please use a has_many :through association instead."
11
- end
12
- end
13
-
14
- def create(attributes = {})
15
- create_record(attributes) { |record| insert_record(record) }
16
10
  end
17
11
 
18
- def create!(attributes = {})
19
- create_record(attributes) { |record| insert_record(record, true) }
20
- end
12
+ def insert_record(record, validate = true)
13
+ return if record.new_record? && !record.save(:validate => validate)
21
14
 
22
- def columns
23
- @reflection.columns(@reflection.options[:join_table], "#{@reflection.options[:join_table]} Columns")
24
- end
15
+ if options[:insert_sql]
16
+ owner.connection.insert(interpolate(options[:insert_sql], record))
17
+ else
18
+ stmt = join_table.compile_insert(
19
+ join_table[reflection.foreign_key] => owner.id,
20
+ join_table[reflection.association_foreign_key] => record.id
21
+ )
25
22
 
26
- def reset_column_information
27
- @reflection.reset_column_information
28
- end
23
+ owner.connection.insert stmt.to_sql
24
+ end
29
25
 
30
- def has_primary_key?
31
- @has_primary_key ||= @owner.connection.supports_primary_key? && @owner.connection.primary_key(@reflection.options[:join_table])
26
+ record
32
27
  end
33
28
 
34
- protected
35
- def construct_find_options!(options)
36
- options[:joins] = Arel::SqlLiteral.new @join_sql
37
- options[:readonly] = finding_with_ambiguous_select?(options[:select] || @reflection.options[:select])
38
- options[:select] ||= (@reflection.options[:select] || Arel::SqlLiteral.new('*'))
39
- end
29
+ private
40
30
 
41
31
  def count_records
42
32
  load_target.size
43
33
  end
44
34
 
45
- def insert_record(record, force = true, validate = true)
46
- if record.new_record?
47
- if force
48
- record.save!
49
- else
50
- return false unless record.save(:validate => validate)
51
- end
52
- end
53
-
54
- if @reflection.options[:insert_sql]
55
- @owner.connection.insert(interpolate_and_sanitize_sql(@reflection.options[:insert_sql], record))
35
+ def delete_records(records, method)
36
+ if sql = options[:delete_sql]
37
+ records.each { |record| owner.connection.delete(interpolate(sql, record)) }
56
38
  else
57
- relation = Arel::Table.new(@reflection.options[:join_table])
58
- timestamps = record_timestamp_columns(record)
59
- timezone = record.send(:current_time_from_proper_timezone) if timestamps.any?
60
-
61
- attributes = Hash[columns.map do |column|
62
- name = column.name
63
- value = case name.to_s
64
- when @reflection.primary_key_name.to_s
65
- @owner.id
66
- when @reflection.association_foreign_key.to_s
67
- record.id
68
- when *timestamps
69
- timezone
70
- else
71
- @owner.send(:quote_value, record[name], column) if record.has_attribute?(name)
72
- end
73
- [relation[name], value] unless value.nil?
74
- end]
75
-
76
- relation.insert(attributes)
39
+ relation = join_table
40
+ stmt = relation.where(relation[reflection.foreign_key].eq(owner.id).
41
+ and(relation[reflection.association_foreign_key].in(records.map { |x| x.id }.compact))
42
+ ).compile_delete
43
+ owner.connection.delete stmt.to_sql
77
44
  end
78
-
79
- return true
80
45
  end
81
46
 
82
- def delete_records(records)
83
- if sql = @reflection.options[:delete_sql]
84
- records.each { |record| @owner.connection.delete(interpolate_and_sanitize_sql(sql, record)) }
85
- else
86
- relation = Arel::Table.new(@reflection.options[:join_table])
87
- relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
88
- and(relation[@reflection.association_foreign_key].in(records.map { |x| x.id }.compact))
89
- ).delete
90
- end
91
- end
92
-
93
- def construct_sql
94
- if @reflection.options[:finder_sql]
95
- @finder_sql = interpolate_and_sanitize_sql(@reflection.options[:finder_sql])
96
- else
97
- @finder_sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{owner_quoted_id} "
98
- @finder_sql << " AND (#{conditions})" if conditions
99
- end
100
-
101
- @join_sql = "INNER JOIN #{@owner.connection.quote_table_name @reflection.options[:join_table]} ON #{@reflection.quoted_table_name}.#{@reflection.klass.primary_key} = #{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.association_foreign_key}"
102
-
103
- construct_counter_sql
104
- end
105
-
106
- def construct_scope
107
- { :find => { :conditions => @finder_sql,
108
- :joins => @join_sql,
109
- :readonly => false,
110
- :order => @reflection.options[:order],
111
- :include => @reflection.options[:include],
112
- :limit => @reflection.options[:limit] } }
113
- end
114
-
115
- # Join tables with additional columns on top of the two foreign keys must be considered
116
- # ambiguous unless a select clause has been explicitly defined. Otherwise you can get
117
- # broken records back, if, for example, the join column also has an id column. This will
118
- # then overwrite the id column of the records coming back.
119
- def finding_with_ambiguous_select?(select_clause)
120
- !select_clause && columns.size != 2
121
- end
122
-
123
- private
124
- def create_record(attributes, &block)
125
- # Can't use Base.create because the foreign key may be a protected attribute.
126
- ensure_owner_is_not_new
127
- if attributes.is_a?(Array)
128
- attributes.collect { |attr| create(attr) }
129
- else
130
- build_record(attributes, &block)
131
- end
132
- end
133
-
134
- def record_timestamp_columns(record)
135
- if record.record_timestamps
136
- record.send(:all_timestamp_attributes).map { |x| x.to_s }
137
- else
138
- []
139
- end
47
+ def invertible_for?(record)
48
+ false
140
49
  end
141
50
  end
142
51
  end
@@ -5,19 +5,14 @@ module ActiveRecord
5
5
  #
6
6
  # If the association has a <tt>:through</tt> option further specialization
7
7
  # is provided by its child HasManyThroughAssociation.
8
- class HasManyAssociation < AssociationCollection #:nodoc:
9
- def initialize(owner, reflection)
10
- @finder_sql = nil
11
- super
8
+ class HasManyAssociation < CollectionAssociation #:nodoc:
9
+
10
+ def insert_record(record, validate = true)
11
+ set_owner_attributes(record)
12
+ record.save(:validate => validate)
12
13
  end
13
- protected
14
- def owner_quoted_id
15
- if @reflection.options[:primary_key]
16
- quote_value(@owner.send(@reflection.options[:primary_key]))
17
- else
18
- @owner.quoted_id
19
- end
20
- end
14
+
15
+ private
21
16
 
22
17
  # Returns the number of records in this collection.
23
18
  #
@@ -34,94 +29,70 @@ module ActiveRecord
34
29
  # the loaded flag is set to true as well.
35
30
  def count_records
36
31
  count = if has_cached_counter?
37
- @owner.send(:read_attribute, cached_counter_attribute_name)
38
- elsif @reflection.options[:finder_sql] || @reflection.options[:counter_sql]
39
- @reflection.klass.count_by_sql(@counter_sql)
32
+ owner.send(:read_attribute, cached_counter_attribute_name)
33
+ elsif options[:counter_sql] || options[:finder_sql]
34
+ reflection.klass.count_by_sql(custom_counter_sql)
40
35
  else
41
- @reflection.klass.count(:conditions => @counter_sql, :include => @reflection.options[:include])
36
+ scoped.count
42
37
  end
43
38
 
44
39
  # If there's nothing in the database and @target has no new records
45
40
  # we are certain the current target is an empty array. This is a
46
41
  # documented side-effect of the method that may avoid an extra SELECT.
47
- @target ||= [] and loaded if count == 0
48
-
49
- if @reflection.options[:limit]
50
- count = [ @reflection.options[:limit], count ].min
51
- end
52
-
53
- return count
54
- end
42
+ @target ||= [] and loaded! if count == 0
55
43
 
56
- def has_cached_counter?
57
- @owner.attribute_present?(cached_counter_attribute_name)
44
+ [options[:limit], count].compact.min
58
45
  end
59
46
 
60
- def cached_counter_attribute_name
61
- "#{@reflection.name}_count"
47
+ def has_cached_counter?(reflection = reflection)
48
+ owner.attribute_present?(cached_counter_attribute_name(reflection))
62
49
  end
63
50
 
64
- def insert_record(record, force = false, validate = true)
65
- set_belongs_to_association_for(record)
66
- force ? record.save! : record.save(:validate => validate)
51
+ def cached_counter_attribute_name(reflection = reflection)
52
+ "#{reflection.name}_count"
67
53
  end
68
54
 
69
- # Deletes the records according to the <tt>:dependent</tt> option.
70
- def delete_records(records)
71
- case @reflection.options[:dependent]
72
- when :destroy
73
- records.each { |r| r.destroy }
74
- when :delete_all
75
- @reflection.klass.delete(records.map { |record| record.id })
76
- else
77
- relation = Arel::Table.new(@reflection.table_name)
78
- relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
79
- and(relation[@reflection.klass.primary_key].in(records.map { |r| r.id }))
80
- ).update(relation[@reflection.primary_key_name] => nil)
81
-
82
- @owner.class.update_counters(@owner.id, cached_counter_attribute_name => -records.size) if has_cached_counter?
55
+ def update_counter(difference, reflection = reflection)
56
+ if has_cached_counter?(reflection)
57
+ counter = cached_counter_attribute_name(reflection)
58
+ owner.class.update_counters(owner.id, counter => difference)
59
+ owner[counter] += difference
60
+ owner.changed_attributes.delete(counter) # eww
83
61
  end
84
62
  end
85
63
 
86
- def target_obsolete?
87
- false
64
+ # This shit is nasty. We need to avoid the following situation:
65
+ #
66
+ # * An associated record is deleted via record.destroy
67
+ # * Hence the callbacks run, and they find a belongs_to on the record with a
68
+ # :counter_cache options which points back at our owner. So they update the
69
+ # counter cache.
70
+ # * In which case, we must make sure to *not* update the counter cache, or else
71
+ # it will be decremented twice.
72
+ #
73
+ # Hence this method.
74
+ def inverse_updates_counter_cache?(reflection = reflection)
75
+ counter_name = cached_counter_attribute_name(reflection)
76
+ reflection.klass.reflect_on_all_associations(:belongs_to).any? { |inverse_reflection|
77
+ inverse_reflection.counter_cache_column == counter_name
78
+ }
88
79
  end
89
80
 
90
- def construct_sql
91
- case
92
- when @reflection.options[:finder_sql]
93
- @finder_sql = interpolate_and_sanitize_sql(@reflection.options[:finder_sql])
94
-
95
- when @reflection.options[:as]
96
- @finder_sql =
97
- "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " +
98
- "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
99
- @finder_sql << " AND (#{conditions})" if conditions
81
+ # Deletes the records according to the <tt>:dependent</tt> option.
82
+ def delete_records(records, method)
83
+ if method == :destroy
84
+ records.each { |r| r.destroy }
85
+ update_counter(-records.length) unless inverse_updates_counter_cache?
86
+ else
87
+ keys = records.map { |r| r[reflection.association_primary_key] }
88
+ scope = scoped.where(reflection.association_primary_key => keys)
100
89
 
90
+ if method == :delete_all
91
+ update_counter(-scope.delete_all)
101
92
  else
102
- @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}"
103
- @finder_sql << " AND (#{conditions})" if conditions
93
+ update_counter(-scope.update_all(reflection.foreign_key => nil))
94
+ end
104
95
  end
105
-
106
- construct_counter_sql
107
- end
108
-
109
- def construct_scope
110
- create_scoping = {}
111
- set_belongs_to_association_for(create_scoping)
112
- {
113
- :find => { :conditions => @finder_sql,
114
- :readonly => false,
115
- :order => @reflection.options[:order],
116
- :limit => @reflection.options[:limit],
117
- :include => @reflection.options[:include]},
118
- :create => create_scoping
119
- }
120
- end
121
-
122
- def we_can_set_the_inverse_on_this?(record)
123
- inverse = @reflection.inverse_of
124
- return !inverse.nil?
125
96
  end
126
97
  end
127
98
  end