activerecord 3.0.3 → 3.0.4.rc1

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 (39) hide show
  1. data/CHANGELOG +6 -0
  2. data/lib/active_record/aggregations.rb +1 -1
  3. data/lib/active_record/association_preload.rb +22 -7
  4. data/lib/active_record/associations.rb +11 -6
  5. data/lib/active_record/associations/association_collection.rb +14 -15
  6. data/lib/active_record/associations/association_proxy.rb +3 -3
  7. data/lib/active_record/associations/belongs_to_association.rb +3 -3
  8. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -0
  9. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +10 -1
  10. data/lib/active_record/associations/has_many_through_association.rb +1 -1
  11. data/lib/active_record/associations/has_one_association.rb +6 -6
  12. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  13. data/lib/active_record/attribute_methods.rb +1 -1
  14. data/lib/active_record/attribute_methods/primary_key.rb +3 -4
  15. data/lib/active_record/attribute_methods/read.rb +2 -1
  16. data/lib/active_record/autosave_association.rb +8 -8
  17. data/lib/active_record/base.rb +9 -11
  18. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -0
  19. data/lib/active_record/connection_adapters/abstract/quoting.rb +2 -1
  20. data/lib/active_record/connection_adapters/abstract_adapter.rb +5 -0
  21. data/lib/active_record/connection_adapters/postgresql_adapter.rb +7 -6
  22. data/lib/active_record/locking/optimistic.rb +1 -1
  23. data/lib/active_record/locking/pessimistic.rb +1 -1
  24. data/lib/active_record/nested_attributes.rb +2 -5
  25. data/lib/active_record/observer.rb +4 -26
  26. data/lib/active_record/persistence.rb +5 -5
  27. data/lib/active_record/reflection.rb +9 -1
  28. data/lib/active_record/relation.rb +1 -1
  29. data/lib/active_record/relation/calculations.rb +24 -24
  30. data/lib/active_record/relation/finder_methods.rb +1 -1
  31. data/lib/active_record/relation/predicate_builder.rb +2 -2
  32. data/lib/active_record/relation/query_methods.rb +24 -6
  33. data/lib/active_record/session_store.rb +4 -4
  34. data/lib/active_record/timestamp.rb +1 -1
  35. data/lib/active_record/transactions.rb +17 -14
  36. data/lib/active_record/validations.rb +1 -1
  37. data/lib/active_record/validations/uniqueness.rb +1 -1
  38. data/lib/active_record/version.rb +4 -3
  39. metadata +20 -15
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ *Rails 3.0.4 (unreleased)*
2
+
3
+ * Added deprecation warning for has_and_belongs_to_many associations where the join table has
4
+ additional attributes other than the keys. Access to these attributes is removed in 3.1.
5
+ Please use has_many :through instead. [Jon Leighton]
6
+
1
7
  *Rails 3.0.3 (November 16, 2010)*
2
8
 
3
9
  * Support find by class like this: Post.where(:name => Post)
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  def clear_aggregation_cache #:nodoc:
7
7
  self.class.reflect_on_all_aggregations.to_a.each do |assoc|
8
8
  instance_variable_set "@#{assoc.name}", nil
9
- end if self.persisted?
9
+ end unless self.new_record?
10
10
  end
11
11
 
12
12
  # Active Record implements aggregation through a macro-like class method called +composed_of+
@@ -193,13 +193,17 @@ module ActiveRecord
193
193
  conditions = "t0.#{reflection.primary_key_name} #{in_or_equals_for_ids(ids)}"
194
194
  conditions << append_conditions(reflection, preload_options)
195
195
 
196
- associated_records = reflection.klass.unscoped.where([conditions, ids]).
196
+ associated_records_proxy = reflection.klass.unscoped.
197
197
  includes(options[:include]).
198
198
  joins("INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}").
199
199
  select("#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id").
200
- order(options[:order]).to_a
200
+ order(options[:order])
201
201
 
202
- set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id')
202
+ all_associated_records = associated_records(ids) do |some_ids|
203
+ associated_records_proxy.where([conditions, ids]).to_a
204
+ end
205
+
206
+ set_association_collection_records(id_to_record_map, reflection.name, all_associated_records, 'the_parent_record_id')
203
207
  end
204
208
 
205
209
  def preload_has_one_association(records, reflection, preload_options={})
@@ -336,9 +340,8 @@ module ActiveRecord
336
340
  klass = klass_name.constantize
337
341
 
338
342
  table_name = klass.quoted_table_name
339
- primary_key = reflection.options[:primary_key] || klass.primary_key
343
+ primary_key = (reflection.options[:primary_key] || klass.primary_key).to_s
340
344
  column_type = klass.columns.detect{|c| c.name == primary_key}.type
341
-
342
345
  ids = id_map.keys.map do |id|
343
346
  if column_type == :integer
344
347
  id.to_i
@@ -374,13 +377,14 @@ module ActiveRecord
374
377
  find_options = {
375
378
  :select => preload_options[:select] || options[:select] || Arel::SqlLiteral.new("#{table_name}.*"),
376
379
  :include => preload_options[:include] || options[:include],
377
- :conditions => [conditions, ids],
378
380
  :joins => options[:joins],
379
381
  :group => preload_options[:group] || options[:group],
380
382
  :order => preload_options[:order] || options[:order]
381
383
  }
382
384
 
383
- reflection.klass.scoped.apply_finder_options(find_options).to_a
385
+ associated_records(ids) do |some_ids|
386
+ reflection.klass.scoped.apply_finder_options(find_options.merge(:conditions => [conditions, some_ids])).to_a
387
+ end
384
388
  end
385
389
 
386
390
 
@@ -398,6 +402,17 @@ module ActiveRecord
398
402
  def in_or_equals_for_ids(ids)
399
403
  ids.size > 1 ? "IN (?)" : "= ?"
400
404
  end
405
+
406
+ # Some databases impose a limit on the number of ids in a list (in Oracle its 1000)
407
+ # Make several smaller queries if necessary or make one query if the adapter supports it
408
+ def associated_records(ids)
409
+ max_ids_in_a_list = connection.ids_in_list_limit || ids.size
410
+ records = []
411
+ ids.each_slice(max_ids_in_a_list) do |some_ids|
412
+ records += yield(some_ids)
413
+ end
414
+ records
415
+ end
401
416
  end
402
417
  end
403
418
  end
@@ -118,7 +118,7 @@ module ActiveRecord
118
118
  def clear_association_cache #:nodoc:
119
119
  self.class.reflect_on_all_associations.to_a.each do |assoc|
120
120
  instance_variable_set "@#{assoc.name}", nil
121
- end if self.persisted?
121
+ end unless self.new_record?
122
122
  end
123
123
 
124
124
  private
@@ -2156,14 +2156,19 @@ module ActiveRecord
2156
2156
  when :has_many, :has_one
2157
2157
  if reflection.options[:through]
2158
2158
  join_table = Arel::Table.new(through_reflection.klass.table_name, :as => aliased_join_table_name, :engine => arel_engine)
2159
- jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil
2159
+ jt_as_extra = jt_source_extra = jt_sti_extra = nil
2160
2160
  first_key = second_key = as_extra = nil
2161
2161
 
2162
- if through_reflection.options[:as] # has_many :through against a polymorphic join
2163
- jt_foreign_key = through_reflection.options[:as].to_s + '_id'
2164
- jt_as_extra = join_table[through_reflection.options[:as].to_s + '_type'].eq(parent.active_record.base_class.name)
2162
+ if through_reflection.macro == :belongs_to
2163
+ jt_primary_key = through_reflection.primary_key_name
2164
+ jt_foreign_key = through_reflection.association_primary_key
2165
2165
  else
2166
+ jt_primary_key = through_reflection.active_record_primary_key
2166
2167
  jt_foreign_key = through_reflection.primary_key_name
2168
+
2169
+ if through_reflection.options[:as] # has_many :through against a polymorphic join
2170
+ jt_as_extra = join_table[through_reflection.options[:as].to_s + '_type'].eq(parent.active_record.base_class.name)
2171
+ end
2167
2172
  end
2168
2173
 
2169
2174
  case source_reflection.macro
@@ -2191,7 +2196,7 @@ module ActiveRecord
2191
2196
  end
2192
2197
 
2193
2198
  [
2194
- [parent_table[parent.primary_key].eq(join_table[jt_foreign_key]), jt_as_extra, jt_source_extra, jt_sti_extra].reject{|x| x.blank? },
2199
+ [parent_table[jt_primary_key].eq(join_table[jt_foreign_key]), jt_as_extra, jt_source_extra, jt_sti_extra].reject{|x| x.blank? },
2195
2200
  aliased_table[first_key].eq(join_table[second_key])
2196
2201
  ]
2197
2202
  elsif reflection.options[:as]
@@ -127,13 +127,13 @@ module ActiveRecord
127
127
  # Since << flattens its argument list and inserts each record, +push+ and +concat+ behave identically.
128
128
  def <<(*records)
129
129
  result = true
130
- load_target unless @owner.persisted?
130
+ load_target if @owner.new_record?
131
131
 
132
132
  transaction do
133
133
  flatten_deeper(records).each do |record|
134
134
  raise_on_type_mismatch(record)
135
135
  add_record_to_target_with_callbacks(record) do |r|
136
- result &&= insert_record(record) if @owner.persisted?
136
+ result &&= insert_record(record) unless @owner.new_record?
137
137
  end
138
138
  end
139
139
  end
@@ -291,12 +291,12 @@ module ActiveRecord
291
291
  # This method is abstract in the sense that it relies on
292
292
  # +count_records+, which is a method descendants have to provide.
293
293
  def size
294
- if !@owner.persisted? || (loaded? && !@reflection.options[:uniq])
294
+ if @owner.new_record? || (loaded? && !@reflection.options[:uniq])
295
295
  @target.size
296
296
  elsif !loaded? && @reflection.options[:group]
297
297
  load_target.size
298
298
  elsif !loaded? && !@reflection.options[:uniq] && @target.is_a?(Array)
299
- unsaved_records = @target.reject { |r| r.persisted? }
299
+ unsaved_records = @target.select { |r| r.new_record? }
300
300
  unsaved_records.size + count_records
301
301
  else
302
302
  count_records
@@ -363,7 +363,7 @@ module ActiveRecord
363
363
 
364
364
  def include?(record)
365
365
  return false unless record.is_a?(@reflection.klass)
366
- return include_in_memory?(record) unless record.persisted?
366
+ return include_in_memory?(record) if record.new_record?
367
367
  load_target if @reflection.options[:finder_sql] && !loaded?
368
368
  return @target.include?(record) if loaded?
369
369
  exists?(record)
@@ -390,7 +390,7 @@ module ActiveRecord
390
390
  end
391
391
 
392
392
  def load_target
393
- if @owner.persisted? || foreign_key_present
393
+ if !@owner.new_record? || foreign_key_present
394
394
  begin
395
395
  if !loaded?
396
396
  if @target.is_a?(Array) && @target.any?
@@ -521,7 +521,7 @@ module ActiveRecord
521
521
 
522
522
  transaction do
523
523
  records.each { |record| callback(:before_remove, record) }
524
- old_records = records.select { |r| r.persisted? }
524
+ old_records = records.reject { |r| r.new_record? }
525
525
  yield(records, old_records)
526
526
  records.each { |record| callback(:after_remove, record) }
527
527
  end
@@ -546,23 +546,22 @@ module ActiveRecord
546
546
  end
547
547
 
548
548
  def ensure_owner_is_not_new
549
- unless @owner.persisted?
549
+ if @owner.new_record?
550
550
  raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
551
551
  end
552
552
  end
553
553
 
554
554
  def fetch_first_or_last_using_find?(args)
555
- args.first.kind_of?(Hash) || !(loaded? || !@owner.persisted? || @reflection.options[:finder_sql] ||
556
- !@target.all? { |record| record.persisted? } || args.first.kind_of?(Integer))
555
+ args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] ||
556
+ @target.any? { |record| record.new_record? } || args.first.kind_of?(Integer))
557
557
  end
558
558
 
559
559
  def include_in_memory?(record)
560
560
  if @reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
561
- @owner.send(proxy_reflection.through_reflection.name.to_sym).map do |source|
562
- source_reflection_target = source.send(proxy_reflection.source_reflection.name)
563
- return true if source_reflection_target.respond_to?(:include?) ? source_reflection_target.include?(record) : source_reflection_target == record
564
- end
565
- false
561
+ @owner.send(proxy_reflection.through_reflection.name).any? { |source|
562
+ target = source.send(proxy_reflection.source_reflection.name)
563
+ target.respond_to?(:include?) ? target.include?(record) : target == record
564
+ } || @target.include?(record)
566
565
  else
567
566
  @target.include?(record)
568
567
  end
@@ -174,10 +174,10 @@ module ActiveRecord
174
174
  # If the association is polymorphic the type of the owner is also set.
175
175
  def set_belongs_to_association_for(record)
176
176
  if @reflection.options[:as]
177
- record["#{@reflection.options[:as]}_id"] = @owner.id if @owner.persisted?
177
+ record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
178
178
  record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
179
179
  else
180
- if @owner.persisted?
180
+ unless @owner.new_record?
181
181
  primary_key = @reflection.options[:primary_key] || :id
182
182
  record[@reflection.primary_key_name] = @owner.send(primary_key)
183
183
  end
@@ -233,7 +233,7 @@ module ActiveRecord
233
233
  def load_target
234
234
  return nil unless defined?(@loaded)
235
235
 
236
- if !loaded? and (@owner.persisted? || foreign_key_present)
236
+ if !loaded? and (!@owner.new_record? || foreign_key_present)
237
237
  @target = find_target
238
238
  end
239
239
 
@@ -14,7 +14,7 @@ module ActiveRecord
14
14
  counter_cache_name = @reflection.counter_cache_column
15
15
 
16
16
  if record.nil?
17
- if counter_cache_name && @owner.persisted?
17
+ if counter_cache_name && !@owner.new_record?
18
18
  @reflection.klass.decrement_counter(counter_cache_name, previous_record_id) if @owner[@reflection.primary_key_name]
19
19
  end
20
20
 
@@ -22,13 +22,13 @@ module ActiveRecord
22
22
  else
23
23
  raise_on_type_mismatch(record)
24
24
 
25
- if counter_cache_name && @owner.persisted? && record.id != @owner[@reflection.primary_key_name]
25
+ if counter_cache_name && !@owner.new_record? && record.id != @owner[@reflection.primary_key_name]
26
26
  @reflection.klass.increment_counter(counter_cache_name, record.id)
27
27
  @reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
28
28
  end
29
29
 
30
30
  @target = (AssociationProxy === record ? record.target : record)
31
- @owner[@reflection.primary_key_name] = record_id(record) if record.persisted?
31
+ @owner[@reflection.primary_key_name] = record_id(record) unless record.new_record?
32
32
  @updated = true
33
33
  end
34
34
 
@@ -23,6 +23,10 @@ module ActiveRecord
23
23
  @updated
24
24
  end
25
25
 
26
+ def conditions
27
+ @conditions ||= interpolate_sql(association_class.send(:sanitize_sql, @reflection.options[:conditions])) if @reflection.options[:conditions]
28
+ end
29
+
26
30
  private
27
31
 
28
32
  # NOTE - for now, we're only supporting inverse setting from belongs_to back onto
@@ -1,7 +1,16 @@
1
+ require 'active_support/deprecation'
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record Has And Belongs To Many Association
3
5
  module Associations
4
6
  class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
7
+ def initialize(owner, reflection)
8
+ 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
+
5
14
  def create(attributes = {})
6
15
  create_record(attributes) { |record| insert_record(record) }
7
16
  end
@@ -34,7 +43,7 @@ module ActiveRecord
34
43
  end
35
44
 
36
45
  def insert_record(record, force = true, validate = true)
37
- unless record.persisted?
46
+ if record.new_record?
38
47
  if force
39
48
  record.save!
40
49
  else
@@ -59,7 +59,7 @@ module ActiveRecord
59
59
  end
60
60
 
61
61
  def insert_record(record, force = true, validate = true)
62
- unless record.persisted?
62
+ if record.new_record?
63
63
  if force
64
64
  record.save!
65
65
  else
@@ -35,18 +35,18 @@ module ActiveRecord
35
35
  if dependent? && !dont_save
36
36
  case @reflection.options[:dependent]
37
37
  when :delete
38
- @target.delete if @target.persisted?
38
+ @target.delete unless @target.new_record?
39
39
  @owner.clear_association_cache
40
40
  when :destroy
41
- @target.destroy if @target.persisted?
41
+ @target.destroy unless @target.new_record?
42
42
  @owner.clear_association_cache
43
43
  when :nullify
44
44
  @target[@reflection.primary_key_name] = nil
45
- @target.save if @owner.persisted? && @target.persisted?
45
+ @target.save unless @owner.new_record? || @target.new_record?
46
46
  end
47
47
  else
48
48
  @target[@reflection.primary_key_name] = nil
49
- @target.save if @owner.persisted? && @target.persisted?
49
+ @target.save unless @owner.new_record? || @target.new_record?
50
50
  end
51
51
  end
52
52
 
@@ -61,7 +61,7 @@ module ActiveRecord
61
61
  set_inverse_instance(obj, @owner)
62
62
  @loaded = true
63
63
 
64
- unless !@owner.persisted? or obj.nil? or dont_save
64
+ unless @owner.new_record? or obj.nil? or dont_save
65
65
  return (obj.save ? self : false)
66
66
  else
67
67
  return (obj.nil? ? nil : self)
@@ -120,7 +120,7 @@ module ActiveRecord
120
120
  if replace_existing
121
121
  replace(record, true)
122
122
  else
123
- record[@reflection.primary_key_name] = @owner.id if @owner.persisted?
123
+ record[@reflection.primary_key_name] = @owner.id unless @owner.new_record?
124
124
  self.target = record
125
125
  set_inverse_instance(record, @owner)
126
126
  end
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  if current_object
22
22
  new_value ? current_object.update_attributes(construct_join_attributes(new_value)) : current_object.destroy
23
23
  elsif new_value
24
- unless @owner.persisted?
24
+ if @owner.new_record?
25
25
  self.target = new_value
26
26
  through_association = @owner.send(:association_instance_get, @reflection.through_reflection.name)
27
27
  through_association.build(construct_join_attributes(new_value))
@@ -54,7 +54,7 @@ module ActiveRecord
54
54
 
55
55
  protected
56
56
  def attribute_method?(attr_name)
57
- attr_name == 'id' || attributes.include?(attr_name)
57
+ attr_name == 'id' || (defined?(@attributes) && @attributes.include?(attr_name))
58
58
  end
59
59
  end
60
60
  end
@@ -3,11 +3,10 @@ module ActiveRecord
3
3
  module PrimaryKey
4
4
  extend ActiveSupport::Concern
5
5
 
6
- # Returns this record's primary key value wrapped in an Array or nil if
7
- # the record is not persisted? or has just been destroyed.
6
+ # Returns this record's primary key value wrapped in an Array
7
+ # or nil if the record is a new_record?
8
8
  def to_key
9
- key = send(self.class.primary_key)
10
- [key] if key
9
+ new_record? ? nil : [ id ]
11
10
  end
12
11
 
13
12
  module ClassMethods
@@ -75,7 +75,8 @@ module ActiveRecord
75
75
  def read_attribute(attr_name)
76
76
  attr_name = attr_name.to_s
77
77
  attr_name = self.class.primary_key if attr_name == 'id'
78
- if !(value = @attributes[attr_name]).nil?
78
+ value = @attributes[attr_name]
79
+ unless value.nil?
79
80
  if column = column_for_attribute(attr_name)
80
81
  if unserializable_attribute?(attr_name, column)
81
82
  unserialize_attribute(attr_name)
@@ -89,7 +89,7 @@ module ActiveRecord
89
89
  # post = Post.create(:title => 'ruby rocks')
90
90
  # post.comments.create(:body => 'hello world')
91
91
  # post.comments[0].body = 'hi everyone'
92
- # post.save # => saves both post and comment, with 'hi everyone' as title
92
+ # post.save # => saves both post and comment, with 'hi everyone' as body
93
93
  #
94
94
  # Destroying one of the associated models as part of the parent's save action
95
95
  # is as simple as marking it for destruction:
@@ -208,7 +208,7 @@ module ActiveRecord
208
208
  # Returns whether or not this record has been changed in any way (including whether
209
209
  # any of its nested autosave associations are likewise changed)
210
210
  def changed_for_autosave?
211
- !persisted? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
211
+ new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
212
212
  end
213
213
 
214
214
  private
@@ -222,7 +222,7 @@ module ActiveRecord
222
222
  elsif autosave
223
223
  association.target.find_all { |record| record.changed_for_autosave? }
224
224
  else
225
- association.target.find_all { |record| !record.persisted? }
225
+ association.target.find_all { |record| record.new_record? }
226
226
  end
227
227
  end
228
228
 
@@ -248,7 +248,7 @@ module ActiveRecord
248
248
  # +reflection+.
249
249
  def validate_collection_association(reflection)
250
250
  if association = association_instance_get(reflection.name)
251
- if records = associated_records_to_validate_or_save(association, !persisted?, reflection.options[:autosave])
251
+ if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave])
252
252
  records.each { |record| association_valid?(reflection, record) }
253
253
  end
254
254
  end
@@ -277,7 +277,7 @@ module ActiveRecord
277
277
  # Is used as a before_save callback to check while saving a collection
278
278
  # association whether or not the parent was a new record before saving.
279
279
  def before_save_collection_association
280
- @new_record_before_save = !persisted?
280
+ @new_record_before_save = new_record?
281
281
  true
282
282
  end
283
283
 
@@ -299,7 +299,7 @@ module ActiveRecord
299
299
 
300
300
  if autosave && record.marked_for_destruction?
301
301
  association.destroy(record)
302
- elsif autosave != false && (@new_record_before_save || !record.persisted?)
302
+ elsif autosave != false && (@new_record_before_save || record.new_record?)
303
303
  if autosave
304
304
  saved = association.send(:insert_record, record, false, false)
305
305
  else
@@ -334,7 +334,7 @@ module ActiveRecord
334
334
  association.destroy
335
335
  else
336
336
  key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
337
- if autosave != false && (!persisted? || !association.persisted? || association[reflection.primary_key_name] != key || autosave)
337
+ if autosave != false && (new_record? || association.new_record? || association[reflection.primary_key_name] != key || autosave)
338
338
  association[reflection.primary_key_name] = key
339
339
  saved = association.save(:validate => !autosave)
340
340
  raise ActiveRecord::Rollback if !saved && autosave
@@ -354,7 +354,7 @@ module ActiveRecord
354
354
  if autosave && association.marked_for_destruction?
355
355
  association.destroy
356
356
  elsif autosave != false
357
- saved = association.save(:validate => !autosave) if !association.persisted? || autosave
357
+ saved = association.save(:validate => !autosave) if association.new_record? || autosave
358
358
 
359
359
  if association.updated?
360
360
  association_id = association.send(reflection.options[:primary_key] || :id)
@@ -205,7 +205,7 @@ module ActiveRecord #:nodoc:
205
205
  #
206
206
  # # No 'Winter' tag exists
207
207
  # winter = Tag.find_or_initialize_by_name("Winter")
208
- # winter.persisted? # false
208
+ # winter.new_record? # true
209
209
  #
210
210
  # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
211
211
  # a list of parameters.
@@ -1393,7 +1393,7 @@ MSG
1393
1393
  def initialize(attributes = nil)
1394
1394
  @attributes = attributes_from_column_definition
1395
1395
  @attributes_cache = {}
1396
- @persisted = false
1396
+ @new_record = true
1397
1397
  @readonly = false
1398
1398
  @destroyed = false
1399
1399
  @marked_for_destruction = false
@@ -1428,7 +1428,7 @@ MSG
1428
1428
  clear_aggregation_cache
1429
1429
  clear_association_cache
1430
1430
  @attributes_cache = {}
1431
- @persisted = false
1431
+ @new_record = true
1432
1432
  ensure_proper_type
1433
1433
 
1434
1434
  populate_with_current_scope_attributes
@@ -1447,8 +1447,7 @@ MSG
1447
1447
  def init_with(coder)
1448
1448
  @attributes = coder['attributes']
1449
1449
  @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {}
1450
- @readonly = @destroyed = @marked_for_destruction = false
1451
- @persisted = true
1450
+ @new_record = @readonly = @destroyed = @marked_for_destruction = false
1452
1451
  _run_find_callbacks
1453
1452
  _run_initialize_callbacks
1454
1453
  end
@@ -1489,7 +1488,7 @@ MSG
1489
1488
  # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
1490
1489
  def cache_key
1491
1490
  case
1492
- when !persisted?
1491
+ when new_record?
1493
1492
  "#{self.class.model_name.cache_key}/new"
1494
1493
  when timestamp = self[:updated_at]
1495
1494
  "#{self.class.model_name.cache_key}/#{id}-#{timestamp.to_s(:number)}"
@@ -1618,9 +1617,8 @@ MSG
1618
1617
  # models are still comparable.
1619
1618
  def ==(comparison_object)
1620
1619
  comparison_object.equal?(self) ||
1621
- comparison_object.instance_of?(self.class) &&
1622
- id.present? &&
1623
- comparison_object.id == id
1620
+ (comparison_object.instance_of?(self.class) &&
1621
+ comparison_object.id == id && !comparison_object.new_record?)
1624
1622
  end
1625
1623
 
1626
1624
  # Delegates to ==
@@ -1665,7 +1663,7 @@ MSG
1665
1663
  # Returns the contents of the record as a nicely formatted string.
1666
1664
  def inspect
1667
1665
  attributes_as_nice_string = self.class.column_names.collect { |name|
1668
- if has_attribute?(name) || !persisted?
1666
+ if has_attribute?(name) || new_record?
1669
1667
  "#{name}: #{attribute_for_inspect(name)}"
1670
1668
  end
1671
1669
  }.compact.join(", ")
@@ -1717,7 +1715,7 @@ MSG
1717
1715
  if include_readonly_attributes || (!include_readonly_attributes && !self.class.readonly_attributes.include?(name))
1718
1716
  value = read_attribute(name)
1719
1717
 
1720
- if value && self.class.serialized_attributes.key?(name)
1718
+ if !value.nil? && self.class.serialized_attributes.key?(name)
1721
1719
  value = YAML.dump value
1722
1720
  end
1723
1721
  attrs[self.class.arel_table[name]] = value
@@ -1,3 +1,4 @@
1
+ require 'thread'
1
2
  require 'monitor'
2
3
  require 'set'
3
4
  require 'active_support/core_ext/module/synchronization'
@@ -26,11 +26,12 @@ module ActiveRecord
26
26
  when Float, Fixnum, Bignum then value.to_s
27
27
  # BigDecimals need to be output in a non-normalized form and quoted.
28
28
  when BigDecimal then value.to_s('F')
29
+ when Symbol then "'#{quote_string(value.to_s)}'"
29
30
  else
30
31
  if value.acts_like?(:date) || value.acts_like?(:time)
31
32
  "'#{quoted_date(value)}'"
32
33
  else
33
- "'#{quote_string(value.to_s)}'"
34
+ "'#{quote_string(value.to_yaml)}'"
34
35
  end
35
36
  end
36
37
  end
@@ -90,6 +90,11 @@ module ActiveRecord
90
90
  false
91
91
  end
92
92
 
93
+ # Does this adapter restrict the number of ids you can use in a list. Oracle has a limit of 1000.
94
+ def ids_in_list_limit
95
+ nil
96
+ end
97
+
93
98
  # QUOTING ==================================================
94
99
 
95
100
  # Override to return the quoted table name. Defaults to column quoting.
@@ -378,10 +378,7 @@ module ActiveRecord
378
378
  # REFERENTIAL INTEGRITY ====================================
379
379
 
380
380
  def supports_disable_referential_integrity?() #:nodoc:
381
- version = query("SHOW server_version")[0][0].split('.')
382
- version[0].to_i >= 8 && version[1].to_i >= 1
383
- rescue
384
- return false
381
+ postgresql_version >= 80100
385
382
  end
386
383
 
387
384
  def disable_referential_integrity #:nodoc:
@@ -897,8 +894,12 @@ module ActiveRecord
897
894
  else
898
895
  # Mimic PGconn.server_version behavior
899
896
  begin
900
- query('SELECT version()')[0][0] =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
901
- ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
897
+ if query('SELECT version()')[0][0] =~ /PostgreSQL ([0-9.]+)/
898
+ major, minor, tiny = $1.split(".")
899
+ (major.to_i * 10000) + (minor.to_i * 100) + tiny.to_i
900
+ else
901
+ 0
902
+ end
902
903
  rescue
903
904
  0
904
905
  end
@@ -109,7 +109,7 @@ module ActiveRecord
109
109
  def destroy #:nodoc:
110
110
  return super unless locking_enabled?
111
111
 
112
- if persisted?
112
+ unless new_record?
113
113
  lock_col = self.class.locking_column
114
114
  previous_value = send(lock_col).to_i
115
115
 
@@ -47,7 +47,7 @@ module ActiveRecord
47
47
  # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
48
48
  # the locked record.
49
49
  def lock!(lock = true)
50
- reload(:lock => lock) if persisted?
50
+ reload(:lock => lock) unless new_record?
51
51
  self
52
52
  end
53
53
  end
@@ -385,11 +385,8 @@ module ActiveRecord
385
385
  # Updates a record with the +attributes+ or marks it for destruction if
386
386
  # +allow_destroy+ is +true+ and has_destroy_flag? returns +true+.
387
387
  def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
388
- if has_destroy_flag?(attributes) && allow_destroy
389
- record.mark_for_destruction
390
- else
391
- record.attributes = attributes.except(*UNASSIGNABLE_KEYS)
392
- end
388
+ record.attributes = attributes.except(*UNASSIGNABLE_KEYS)
389
+ record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy
393
390
  end
394
391
 
395
392
  # Determines if a hash contains a truthy _destroy key.
@@ -89,51 +89,29 @@ module ActiveRecord
89
89
  # singletons and that call instantiates and registers them.
90
90
  #
91
91
  class Observer < ActiveModel::Observer
92
- class_attribute :observed_methods
93
- self.observed_methods = [].freeze
94
92
 
95
93
  def initialize
96
94
  super
97
95
  observed_descendants.each { |klass| add_observer!(klass) }
98
96
  end
99
97
 
100
- def self.method_added(method)
101
- method = method.to_sym
102
-
103
- if ActiveRecord::Callbacks::CALLBACKS.include?(method)
104
- self.observed_methods += [method]
105
- self.observed_methods.freeze
106
- end
107
- end
108
-
109
98
  protected
110
99
 
111
100
  def observed_descendants
112
101
  observed_classes.sum([]) { |klass| klass.descendants }
113
102
  end
114
103
 
115
- def observe_callbacks?
116
- self.class.observed_methods.any?
117
- end
118
-
119
104
  def add_observer!(klass)
120
105
  super
121
- define_callbacks klass if observe_callbacks?
106
+ define_callbacks klass
122
107
  end
123
108
 
124
109
  def define_callbacks(klass)
125
- existing_methods = klass.instance_methods.map { |m| m.to_sym }
126
110
  observer = self
127
- observer_name = observer.class.name.underscore.gsub('/', '__')
128
111
 
129
- self.class.observed_methods.each do |method|
130
- callback = :"_notify_#{observer_name}_for_#{method}"
131
- unless existing_methods.include? callback
132
- klass.send(:define_method, callback) do # def _notify_user_observer_for_before_save
133
- observer.update(method, self) # observer.update(:before_save, self)
134
- end # end
135
- klass.send(method, callback) # before_save :_notify_user_observer_for_before_save
136
- end
112
+ ActiveRecord::Callbacks::CALLBACKS.each do |callback|
113
+ next unless respond_to?(callback)
114
+ klass.send(callback){|record| observer.send(callback, record)}
137
115
  end
138
116
  end
139
117
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  # Returns true if this object hasn't been saved yet -- that is, a record
5
5
  # for the object doesn't exist in the data store yet; otherwise, returns false.
6
6
  def new_record?
7
- !@persisted
7
+ @new_record
8
8
  end
9
9
 
10
10
  # Returns true if this object has been destroyed, otherwise returns false.
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  # Returns if the record is persisted, i.e. it's not a new record and it was
16
16
  # not destroyed.
17
17
  def persisted?
18
- @persisted && !destroyed?
18
+ !(new_record? || destroyed?)
19
19
  end
20
20
 
21
21
  # :call-seq:
@@ -97,7 +97,7 @@ module ActiveRecord
97
97
  became = klass.new
98
98
  became.instance_variable_set("@attributes", @attributes)
99
99
  became.instance_variable_set("@attributes_cache", @attributes_cache)
100
- became.instance_variable_set("@persisted", persisted?)
100
+ became.instance_variable_set("@new_record", new_record?)
101
101
  became.instance_variable_set("@destroyed", destroyed?)
102
102
  became
103
103
  end
@@ -243,7 +243,7 @@ module ActiveRecord
243
243
  private
244
244
  def create_or_update
245
245
  raise ReadOnlyRecord if readonly?
246
- result = persisted? ? update : create
246
+ result = new_record? ? create : update
247
247
  result != false
248
248
  end
249
249
 
@@ -272,7 +272,7 @@ module ActiveRecord
272
272
 
273
273
  self.id ||= new_id
274
274
 
275
- @persisted = true
275
+ @new_record = false
276
276
  id
277
277
  end
278
278
 
@@ -207,7 +207,15 @@ module ActiveRecord
207
207
  end
208
208
 
209
209
  def association_foreign_key
210
- @association_foreign_key ||= @options[:association_foreign_key] || class_name.foreign_key
210
+ @association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
211
+ end
212
+
213
+ def association_primary_key
214
+ @association_primary_key ||= options[:primary_key] || klass.primary_key
215
+ end
216
+
217
+ def active_record_primary_key
218
+ @active_record_primary_key ||= options[:primary_key] || active_record.primary_key
211
219
  end
212
220
 
213
221
  def counter_cache_column
@@ -376,7 +376,7 @@ module ActiveRecord
376
376
 
377
377
  def references_eager_loaded_tables?
378
378
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
379
- joined_tables = (tables_in_string(arel.joins(arel)) + [table.name, table.table_alias]).compact.map{ |t| t.downcase }.uniq
379
+ joined_tables = (tables_in_string(arel.join_sql) + [table.name, table.table_alias]).compact.map{ |t| t.downcase }.uniq
380
380
  (tables_in_string(to_sql) - joined_tables).any?
381
381
  end
382
382
 
@@ -166,7 +166,7 @@ module ActiveRecord
166
166
  if operation == "count"
167
167
  column_name ||= (select_for_count || :all)
168
168
 
169
- if arel.joins(arel) =~ /LEFT OUTER/i
169
+ if arel.join_sql =~ /LEFT OUTER/i
170
170
  distinct = true
171
171
  column_name = @klass.primary_key if column_name == :all
172
172
  end
@@ -208,14 +208,19 @@ module ActiveRecord
208
208
  end
209
209
 
210
210
  def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
211
- group_attr = @group_values.first
212
- association = @klass.reflect_on_association(group_attr.to_sym)
213
- associated = association && association.macro == :belongs_to # only count belongs_to associations
214
- group_field = associated ? association.primary_key_name : group_attr
215
- group_alias = column_alias_for(group_field)
216
- group_column = column_for(group_field)
211
+ group_attr = @group_values
212
+ association = @klass.reflect_on_association(group_attr.first.to_sym)
213
+ associated = group_attr.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations
214
+ group_fields = Array(associated ? association.primary_key_name : group_attr)
215
+ group_aliases = []
216
+ group_columns = {}
217
+
218
+ group_fields.each do |field|
219
+ group_aliases << column_alias_for(field)
220
+ group_columns[column_alias_for(field)] = column_for(field)
221
+ end
217
222
 
218
- group = @klass.connection.adapter_name == 'FrontBase' ? group_alias : group_field
223
+ group = @klass.connection.adapter_name == 'FrontBase' ? group_aliases : group_fields
219
224
 
220
225
  if operation == 'count' && column_name == :all
221
226
  aggregate_alias = 'count_all'
@@ -223,22 +228,21 @@ module ActiveRecord
223
228
  aggregate_alias = column_alias_for(operation, column_name)
224
229
  end
225
230
 
226
- relation = except(:group).group(group)
227
- relation.select_values = [
228
- operation_over_aggregate_column(aggregate_column(column_name), operation, distinct).as(aggregate_alias),
229
- "#{group_field} AS #{group_alias}"
230
- ]
231
+ relation = except(:group).group(group.join(','))
232
+ relation.select_values = [ operation_over_aggregate_column(aggregate_column(column_name), operation, distinct).as(aggregate_alias) ]
233
+ group_fields.each_index{ |i| relation.select_values << "#{group_fields[i]} AS #{group_aliases[i]}" }
231
234
 
232
235
  calculated_data = @klass.connection.select_all(relation.to_sql)
233
236
 
234
237
  if association
235
- key_ids = calculated_data.collect { |row| row[group_alias] }
238
+ key_ids = calculated_data.collect { |row| row[group_aliases.first] }
236
239
  key_records = association.klass.base_class.find(key_ids)
237
240
  key_records = Hash[key_records.map { |r| [r.id, r] }]
238
241
  end
239
242
 
240
243
  ActiveSupport::OrderedHash[calculated_data.map do |row|
241
- key = type_cast_calculated_value(row[group_alias], group_column)
244
+ key = group_aliases.map{|group_alias| type_cast_calculated_value(row[group_alias], group_columns[group_alias])}
245
+ key = key.first if key.size == 1
242
246
  key = key_records[key] if associated
243
247
  [key, type_cast_calculated_value(row[aggregate_alias], column_for(column_name), operation)]
244
248
  end]
@@ -269,15 +273,11 @@ module ActiveRecord
269
273
  end
270
274
 
271
275
  def type_cast_calculated_value(value, column, operation = nil)
272
- if value.is_a?(String) || value.nil?
273
- case operation
274
- when 'count' then value.to_i
275
- when 'sum' then type_cast_using_column(value || '0', column)
276
- when 'average' then value.try(:to_d)
277
- else type_cast_using_column(value, column)
278
- end
279
- else
280
- type_cast_using_column(value, column)
276
+ case operation
277
+ when 'count' then value.to_i
278
+ when 'sum' then type_cast_using_column(value || '0', column)
279
+ when 'average' then value.try(:to_d)
280
+ else type_cast_using_column(value, column)
281
281
  end
282
282
  end
283
283
 
@@ -194,7 +194,7 @@ module ActiveRecord
194
194
 
195
195
  def construct_relation_for_association_calculations
196
196
  including = (@eager_load_values + @includes_values).uniq
197
- join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, arel.joins(arel))
197
+ join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, arel.join_sql)
198
198
  relation = except(:includes, :eager_load, :preload)
199
199
  apply_join_dependency(relation, join_dependency)
200
200
  end
@@ -25,13 +25,13 @@ module ActiveRecord
25
25
  case value
26
26
  when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation
27
27
  values = value.to_a.map { |x|
28
- x.respond_to?(:quoted_id) ? x.quoted_id : x
28
+ x.is_a?(ActiveRecord::Base) ? x.id : x
29
29
  }
30
30
  attribute.in(values)
31
31
  when Range, Arel::Relation
32
32
  attribute.in(value)
33
33
  when ActiveRecord::Base
34
- attribute.eq(value.quoted_id)
34
+ attribute.eq(value.id)
35
35
  when Class
36
36
  # FIXME: I think we need to deprecate this behavior
37
37
  attribute.eq(value.name)
@@ -143,7 +143,7 @@ module ActiveRecord
143
143
  "#{@klass.table_name}.#{@klass.primary_key} DESC" :
144
144
  reverse_sql_order(order_clause)
145
145
 
146
- relation.order(Arel::SqlLiteral.new(order))
146
+ relation.order(Arel.sql(order))
147
147
  end
148
148
 
149
149
  def arel
@@ -168,7 +168,7 @@ module ActiveRecord
168
168
  arel.join(join)
169
169
  end
170
170
 
171
- arel.joins(arel)
171
+ arel.join_sql
172
172
  end
173
173
 
174
174
  def build_arel
@@ -176,10 +176,7 @@ module ActiveRecord
176
176
 
177
177
  arel = build_joins(arel, @joins_values) unless @joins_values.empty?
178
178
 
179
- (@where_values - ['']).uniq.each do |where|
180
- where = Arel.sql(where) if String === where
181
- arel = arel.where(Arel::Nodes::Grouping.new(where))
182
- end
179
+ arel = collapse_wheres(arel, (@where_values - ['']).uniq)
183
180
 
184
181
  arel = arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?
185
182
 
@@ -200,6 +197,27 @@ module ActiveRecord
200
197
 
201
198
  private
202
199
 
200
+ def collapse_wheres(arel, wheres)
201
+ equalities = wheres.grep(Arel::Nodes::Equality)
202
+
203
+ groups = equalities.group_by do |equality|
204
+ equality.left
205
+ end
206
+
207
+ groups.each do |_, eqls|
208
+ test = eqls.inject(eqls.shift) do |memo, expr|
209
+ memo.or(expr)
210
+ end
211
+ arel = arel.where(test)
212
+ end
213
+
214
+ (wheres - equalities).each do |where|
215
+ where = Arel.sql(where) if String === where
216
+ arel = arel.where(Arel::Nodes::Grouping.new(where))
217
+ end
218
+ arel
219
+ end
220
+
203
221
  def build_where(opts, other = [])
204
222
  case opts
205
223
  when String, Array
@@ -228,7 +228,7 @@ module ActiveRecord
228
228
  @session_id = attributes[:session_id]
229
229
  @data = attributes[:data]
230
230
  @marshaled_data = attributes[:marshaled_data]
231
- @persisted = !@marshaled_data.nil?
231
+ @new_record = @marshaled_data.nil?
232
232
  end
233
233
 
234
234
  # Lazy-unmarshal session state.
@@ -252,8 +252,8 @@ module ActiveRecord
252
252
  marshaled_data = self.class.marshal(data)
253
253
  connect = connection
254
254
 
255
- unless @persisted
256
- @persisted = true
255
+ if @new_record
256
+ @new_record = false
257
257
  connect.update <<-end_sql, 'Create session'
258
258
  INSERT INTO #{table_name} (
259
259
  #{connect.quote_column_name(session_id_column)},
@@ -272,7 +272,7 @@ module ActiveRecord
272
272
  end
273
273
 
274
274
  def destroy
275
- return unless @persisted
275
+ return if @new_record
276
276
 
277
277
  connect = connection
278
278
  connect.delete <<-end_sql, 'Destroy session'
@@ -65,7 +65,7 @@ module ActiveRecord
65
65
  end
66
66
 
67
67
  def timestamp_attributes_for_update_in_model
68
- timestamp_attributes_for_update.select { |c| respond_to?(c) }
68
+ timestamp_attributes_for_update.select { |c| self.class.column_names.include?(c.to_s) }
69
69
  end
70
70
 
71
71
  def timestamp_attributes_for_update #:nodoc:
@@ -130,7 +130,7 @@ module ActiveRecord
130
130
  #
131
131
  # +transaction+ calls can be nested. By default, this makes all database
132
132
  # statements in the nested transaction block become part of the parent
133
- # transaction. For example:
133
+ # transaction. For example, the following behavior may be surprising:
134
134
  #
135
135
  # User.transaction do
136
136
  # User.create(:username => 'Kotori')
@@ -140,12 +140,15 @@ module ActiveRecord
140
140
  # end
141
141
  # end
142
142
  #
143
- # User.find(:all) # => empty
143
+ # creates both "Kotori" and "Nemu". Reason is the <tt>ActiveRecord::Rollback</tt>
144
+ # exception in the nested block does not issue a ROLLBACK. Since these exceptions
145
+ # are captured in transaction blocks, the parent block does not see it and the
146
+ # real transaction is committed.
144
147
  #
145
- # It is also possible to requires a sub-transaction by passing
146
- # <tt>:requires_new => true</tt>. If anything goes wrong, the
147
- # database rolls back to the beginning of the sub-transaction
148
- # without rolling back the parent transaction. For example:
148
+ # In order to get a ROLLBACK for the nested transaction you may ask for a real
149
+ # sub-transaction by passing <tt>:requires_new => true</tt>. If anything goes wrong,
150
+ # the database rolls back to the beginning of the sub-transaction without rolling
151
+ # back the parent transaction. If we add it to the previous example:
149
152
  #
150
153
  # User.transaction do
151
154
  # User.create(:username => 'Kotori')
@@ -155,12 +158,12 @@ module ActiveRecord
155
158
  # end
156
159
  # end
157
160
  #
158
- # User.find(:all) # => Returns only Kotori
161
+ # only "Kotori" is created. (This works on MySQL and PostgreSQL, but not on SQLite3.)
159
162
  #
160
163
  # Most databases don't support true nested transactions. At the time of
161
164
  # writing, the only database that we're aware of that supports true nested
162
165
  # transactions, is MS-SQL. Because of this, Active Record emulates nested
163
- # transactions by using savepoints. See
166
+ # transactions by using savepoints on MySQL and PostgreSQL. See
164
167
  # http://dev.mysql.com/doc/refman/5.0/en/savepoints.html
165
168
  # for more information about savepoints.
166
169
  #
@@ -242,7 +245,7 @@ module ActiveRecord
242
245
  with_transaction_returning_status { super }
243
246
  end
244
247
 
245
- # Reset id and @persisted if the transaction rolls back.
248
+ # Reset id and @new_record if the transaction rolls back.
246
249
  def rollback_active_record_state!
247
250
  remember_transaction_record_state
248
251
  yield
@@ -297,9 +300,9 @@ module ActiveRecord
297
300
  # Save the new record state and id of a record so it can be restored later if a transaction fails.
298
301
  def remember_transaction_record_state #:nodoc
299
302
  @_start_transaction_state ||= {}
300
- unless @_start_transaction_state.include?(:persisted)
303
+ unless @_start_transaction_state.include?(:new_record)
301
304
  @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
302
- @_start_transaction_state[:persisted] = @persisted
305
+ @_start_transaction_state[:new_record] = @new_record
303
306
  end
304
307
  unless @_start_transaction_state.include?(:destroyed)
305
308
  @_start_transaction_state[:destroyed] = @destroyed
@@ -323,7 +326,7 @@ module ActiveRecord
323
326
  restore_state = remove_instance_variable(:@_start_transaction_state)
324
327
  if restore_state
325
328
  @attributes = @attributes.dup if @attributes.frozen?
326
- @persisted = restore_state[:persisted]
329
+ @new_record = restore_state[:new_record]
327
330
  @destroyed = restore_state[:destroyed]
328
331
  if restore_state[:id]
329
332
  self.id = restore_state[:id]
@@ -345,11 +348,11 @@ module ActiveRecord
345
348
  def transaction_include_action?(action) #:nodoc
346
349
  case action
347
350
  when :create
348
- transaction_record_state(:new_record) || !transaction_record_state(:persisted)
351
+ transaction_record_state(:new_record)
349
352
  when :destroy
350
353
  destroyed?
351
354
  when :update
352
- !(transaction_record_state(:new_record) || !transaction_record_state(:persisted) || destroyed?)
355
+ !(transaction_record_state(:new_record) || destroyed?)
353
356
  end
354
357
  end
355
358
  end
@@ -51,7 +51,7 @@ module ActiveRecord
51
51
 
52
52
  # Runs all the specified validations and returns true if no errors were added otherwise false.
53
53
  def valid?(context = nil)
54
- context ||= (persisted? ? :update : :create)
54
+ context ||= (new_record? ? :create : :update)
55
55
  output = super(context)
56
56
 
57
57
  deprecated_callback_method(:validate)
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  relation = relation.where(scope_item => scope_value)
32
32
  end
33
33
 
34
- if record.persisted?
34
+ unless record.new_record?
35
35
  # TODO : This should be in Arel
36
36
  relation = relation.where("#{record.class.quoted_table_name}.#{record.class.primary_key} <> ?", record.send(:id))
37
37
  end
@@ -2,8 +2,9 @@ module ActiveRecord
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 0
5
- TINY = 1
6
-
7
- STRING = [MAJOR, MINOR, TINY].join('.')
5
+ TINY = 4
6
+ PRE = "rc1"
7
+
8
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
8
9
  end
9
10
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
5
- prerelease: false
4
+ hash: 977940590
5
+ prerelease: true
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 3
10
- version: 3.0.3
9
+ - 4
10
+ - rc1
11
+ version: 3.0.4.rc1
11
12
  platform: ruby
12
13
  authors:
13
14
  - David Heinemeier Hansson
@@ -15,7 +16,7 @@ autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2010-11-16 00:00:00 -06:00
19
+ date: 2011-01-31 00:00:00 +13:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
@@ -26,12 +27,13 @@ dependencies:
26
27
  requirements:
27
28
  - - "="
28
29
  - !ruby/object:Gem::Version
29
- hash: 1
30
+ hash: 977940590
30
31
  segments:
31
32
  - 3
32
33
  - 0
33
- - 3
34
- version: 3.0.3
34
+ - 4
35
+ - rc1
36
+ version: 3.0.4.rc1
35
37
  type: :runtime
36
38
  version_requirements: *id001
37
39
  - !ruby/object:Gem::Dependency
@@ -42,12 +44,13 @@ dependencies:
42
44
  requirements:
43
45
  - - "="
44
46
  - !ruby/object:Gem::Version
45
- hash: 1
47
+ hash: 977940590
46
48
  segments:
47
49
  - 3
48
50
  - 0
49
- - 3
50
- version: 3.0.3
51
+ - 4
52
+ - rc1
53
+ version: 3.0.4.rc1
51
54
  type: :runtime
52
55
  version_requirements: *id002
53
56
  - !ruby/object:Gem::Dependency
@@ -208,12 +211,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
208
211
  required_rubygems_version: !ruby/object:Gem::Requirement
209
212
  none: false
210
213
  requirements:
211
- - - ">="
214
+ - - ">"
212
215
  - !ruby/object:Gem::Version
213
- hash: 3
216
+ hash: 25
214
217
  segments:
215
- - 0
216
- version: "0"
218
+ - 1
219
+ - 3
220
+ - 1
221
+ version: 1.3.1
217
222
  requirements: []
218
223
 
219
224
  rubyforge_project: activerecord