activerecord 3.2.3 → 3.2.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 (30) hide show
  1. data/CHANGELOG.md +10 -1
  2. data/README.rdoc +1 -1
  3. data/lib/active_record/associations/collection_association.rb +14 -2
  4. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -5
  5. data/lib/active_record/associations/has_many_association.rb +6 -2
  6. data/lib/active_record/associations/has_many_through_association.rb +4 -0
  7. data/lib/active_record/associations/preloader/association.rb +3 -2
  8. data/lib/active_record/attribute_methods.rb +1 -0
  9. data/lib/active_record/attribute_methods/read.rb +6 -5
  10. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -0
  11. data/lib/active_record/base.rb +3 -4
  12. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +20 -14
  13. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +9 -1
  14. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -1
  15. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -1
  16. data/lib/active_record/connection_adapters/postgresql_adapter.rb +19 -8
  17. data/lib/active_record/connection_adapters/sqlite_adapter.rb +8 -1
  18. data/lib/active_record/fixtures.rb +26 -10
  19. data/lib/active_record/identity_map.rb +7 -1
  20. data/lib/active_record/inheritance.rb +16 -9
  21. data/lib/active_record/railtie.rb +7 -1
  22. data/lib/active_record/railties/databases.rake +2 -2
  23. data/lib/active_record/relation.rb +2 -0
  24. data/lib/active_record/relation/finder_methods.rb +1 -2
  25. data/lib/active_record/scoping/named.rb +3 -3
  26. data/lib/active_record/transactions.rb +3 -1
  27. data/lib/active_record/validations/uniqueness.rb +3 -3
  28. data/lib/active_record/version.rb +2 -2
  29. data/lib/rails/generators/active_record/migration/templates/migration.rb +2 -2
  30. metadata +40 -34
@@ -1,4 +1,13 @@
1
- ## Rails 3.2.3 (unreleased) ##
1
+ ## Rails 3.2.4 (unreleased) ##
2
+
3
+ * Perf fix: Don't load the records when doing assoc.delete_all.
4
+ GH #6289. *Jon Leighton*
5
+
6
+ * Association preloading shouldn't be affected by the current scoping.
7
+ This could cause infinite recursion and potentially other problems.
8
+ See GH #5667. *Jon Leighton*
9
+
10
+ ## Rails 3.2.3 (March 30, 2012) ##
2
11
 
3
12
  * Added find_or_create_by_{attribute}! dynamic method. *Andrew White*
4
13
 
@@ -203,7 +203,7 @@ The latest version of Active Record can be installed with RubyGems:
203
203
 
204
204
  Source code can be downloaded as part of the Rails project on GitHub
205
205
 
206
- * https://github.com/rails/rails/tree/master/activerecord
206
+ * https://github.com/rails/rails/tree/3-2-stable/activerecord
207
207
 
208
208
 
209
209
  == License
@@ -154,7 +154,7 @@ module ActiveRecord
154
154
  #
155
155
  # See delete for more info.
156
156
  def delete_all
157
- delete(load_target).tap do
157
+ delete(:all).tap do
158
158
  reset
159
159
  loaded!
160
160
  end
@@ -226,7 +226,17 @@ module ActiveRecord
226
226
  # are actually removed from the database, that depends precisely on
227
227
  # +delete_records+. They are in any case removed from the collection.
228
228
  def delete(*records)
229
- delete_or_destroy(records, options[:dependent])
229
+ dependent = options[:dependent]
230
+
231
+ if records.first == :all
232
+ if loaded? || dependent == :destroy
233
+ delete_or_destroy(load_target, dependent)
234
+ else
235
+ delete_records(:all, dependent)
236
+ end
237
+ else
238
+ delete_or_destroy(records, dependent)
239
+ end
230
240
  end
231
241
 
232
242
  # Destroy +records+ and remove them from this association calling
@@ -481,6 +491,8 @@ module ActiveRecord
481
491
  raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
482
492
  "new records could not be saved."
483
493
  end
494
+
495
+ target
484
496
  end
485
497
 
486
498
  def concat_records(records)
@@ -44,13 +44,20 @@ module ActiveRecord
44
44
 
45
45
  def delete_records(records, method)
46
46
  if sql = options[:delete_sql]
47
+ records = load_target if records == :all
47
48
  records.each { |record| owner.connection.delete(interpolate(sql, record)) }
48
49
  else
49
- relation = join_table
50
- stmt = relation.where(relation[reflection.foreign_key].eq(owner.id).
51
- and(relation[reflection.association_foreign_key].in(records.map { |x| x.id }.compact))
52
- ).compile_delete
53
- owner.connection.delete stmt
50
+ relation = join_table
51
+ condition = relation[reflection.foreign_key].eq(owner.id)
52
+
53
+ unless records == :all
54
+ condition = condition.and(
55
+ relation[reflection.association_foreign_key].
56
+ in(records.map { |x| x.id }.compact)
57
+ )
58
+ end
59
+
60
+ owner.connection.delete(relation.where(condition).compile_delete)
54
61
  end
55
62
  end
56
63
 
@@ -89,8 +89,12 @@ module ActiveRecord
89
89
  records.each { |r| r.destroy }
90
90
  update_counter(-records.length) unless inverse_updates_counter_cache?
91
91
  else
92
- keys = records.map { |r| r[reflection.association_primary_key] }
93
- scope = scoped.where(reflection.association_primary_key => keys)
92
+ if records == :all
93
+ scope = scoped
94
+ else
95
+ keys = records.map { |r| r[reflection.association_primary_key] }
96
+ scope = scoped.where(reflection.association_primary_key => keys)
97
+ end
94
98
 
95
99
  if method == :delete_all
96
100
  update_counter(-scope.delete_all)
@@ -126,6 +126,10 @@ module ActiveRecord
126
126
  def delete_records(records, method)
127
127
  ensure_not_nested
128
128
 
129
+ # This is unoptimised; it will load all the target records
130
+ # even when we just want to delete everything.
131
+ records = load_target if records == :all
132
+
129
133
  scope = through_association.scoped.where(construct_join_attributes(*records))
130
134
 
131
135
  case method
@@ -77,7 +77,7 @@ module ActiveRecord
77
77
  # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
78
78
  # Make several smaller queries if necessary or make one query if the adapter supports it
79
79
  sliced = owner_keys.each_slice(model.connection.in_clause_length || owner_keys.size)
80
- records = sliced.map { |slice| records_for(slice) }.flatten
80
+ records = sliced.map { |slice| records_for(slice).to_a }.flatten
81
81
  end
82
82
 
83
83
  # Each record may have multiple owners, and vice-versa
@@ -93,7 +93,8 @@ module ActiveRecord
93
93
  end
94
94
 
95
95
  def build_scope
96
- scope = klass.scoped
96
+ scope = klass.unscoped
97
+ scope.default_scoped = true
97
98
 
98
99
  scope = scope.where(process_conditions(options[:conditions]))
99
100
  scope = scope.where(process_conditions(preload_options[:conditions]))
@@ -64,6 +64,7 @@ module ActiveRecord
64
64
  return if attribute_methods_generated?
65
65
  superclass.define_attribute_methods unless self == base_class
66
66
  super(column_names)
67
+ column_names.each { |name| define_external_attribute_method(name) }
67
68
  @attribute_methods_generated = true
68
69
  end
69
70
  end
@@ -67,26 +67,27 @@ module ActiveRecord
67
67
  # we first define with the __temp__ identifier, and then use alias method to
68
68
  # rename it to what we want.
69
69
  def define_method_attribute(attr_name)
70
- cast_code = attribute_cast_code(attr_name)
71
-
72
70
  generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
73
71
  def __temp__
74
- #{internal_attribute_access_code(attr_name, cast_code)}
72
+ #{internal_attribute_access_code(attr_name, attribute_cast_code(attr_name))}
75
73
  end
76
74
  alias_method '#{attr_name}', :__temp__
77
75
  undef_method :__temp__
78
76
  STR
77
+ end
79
78
 
79
+ private
80
+
81
+ def define_external_attribute_method(attr_name)
80
82
  generated_external_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
81
83
  def __temp__(v, attributes, attributes_cache, attr_name)
82
- #{external_attribute_access_code(attr_name, cast_code)}
84
+ #{external_attribute_access_code(attr_name, attribute_cast_code(attr_name))}
83
85
  end
84
86
  alias_method '#{attr_name}', :__temp__
85
87
  undef_method :__temp__
86
88
  STR
87
89
  end
88
90
 
89
- private
90
91
  def cacheable_column?(column)
91
92
  attribute_types_cached_by_default.include?(column.type)
92
93
  end
@@ -43,6 +43,7 @@ module ActiveRecord
43
43
  end
44
44
  time = time.in_time_zone rescue nil if time
45
45
  write_attribute(:#{attr_name}, original_time)
46
+ #{attr_name}_will_change!
46
47
  @attributes_cache["#{attr_name}"] = time
47
48
  end
48
49
  EOV
@@ -450,12 +450,12 @@ module ActiveRecord #:nodoc:
450
450
  private
451
451
 
452
452
  def relation #:nodoc:
453
- @relation ||= Relation.new(self, arel_table)
453
+ relation ||= Relation.new(self, arel_table)
454
454
 
455
455
  if finder_needs_type_condition?
456
- @relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
456
+ relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
457
457
  else
458
- @relation
458
+ relation
459
459
  end
460
460
  end
461
461
  end
@@ -489,7 +489,6 @@ module ActiveRecord #:nodoc:
489
489
  @marked_for_destruction = false
490
490
  @previously_changed = {}
491
491
  @changed_attributes = {}
492
- @relation = nil
493
492
 
494
493
  ensure_proper_type
495
494
 
@@ -92,14 +92,18 @@ module ActiveRecord
92
92
  # #connection can be called any number of times; the connection is
93
93
  # held in a hash keyed by the thread id.
94
94
  def connection
95
- @reserved_connections[current_connection_id] ||= checkout
95
+ synchronize do
96
+ @reserved_connections[current_connection_id] ||= checkout
97
+ end
96
98
  end
97
99
 
98
100
  # Is there an open connection that is being used for the current thread?
99
101
  def active_connection?
100
- @reserved_connections.fetch(current_connection_id) {
101
- return false
102
- }.in_use?
102
+ synchronize do
103
+ @reserved_connections.fetch(current_connection_id) {
104
+ return false
105
+ }.in_use?
106
+ end
103
107
  end
104
108
 
105
109
  # Signal that the thread is finished with the current connection.
@@ -286,17 +290,19 @@ connection. For example: ActiveRecord::Base.connection.close
286
290
  private
287
291
 
288
292
  def release(conn)
289
- thread_id = nil
290
-
291
- if @reserved_connections[current_connection_id] == conn
292
- thread_id = current_connection_id
293
- else
294
- thread_id = @reserved_connections.keys.find { |k|
295
- @reserved_connections[k] == conn
296
- }
297
- end
293
+ synchronize do
294
+ thread_id = nil
295
+
296
+ if @reserved_connections[current_connection_id] == conn
297
+ thread_id = current_connection_id
298
+ else
299
+ thread_id = @reserved_connections.keys.find { |k|
300
+ @reserved_connections[k] == conn
301
+ }
302
+ end
298
303
 
299
- @reserved_connections.delete thread_id if thread_id
304
+ @reserved_connections.delete thread_id if thread_id
305
+ end
300
306
  end
301
307
 
302
308
  def new_connection
@@ -269,7 +269,15 @@ module ActiveRecord
269
269
  # remove_column(:suppliers, :qualification)
270
270
  # remove_columns(:suppliers, :qualification, :experience)
271
271
  def remove_column(table_name, *column_names)
272
- columns_for_remove(table_name, *column_names).each {|column_name| execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{column_name}" }
272
+ if column_names.flatten!
273
+ message = 'Passing array to remove_columns is deprecated, please use ' +
274
+ 'multiple arguments, like: `remove_columns(:posts, :foo, :bar)`'
275
+ ActiveSupport::Deprecation.warn message, caller
276
+ end
277
+
278
+ columns_for_remove(table_name, *column_names).each do |column_name|
279
+ execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{column_name}"
280
+ end
273
281
  end
274
282
  alias :remove_columns :remove_column
275
283
 
@@ -525,7 +525,7 @@ module ActiveRecord
525
525
  def pk_and_sequence_for(table)
526
526
  execute_and_free("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA') do |result|
527
527
  create_table = each_hash(result).first[:"Create Table"]
528
- if create_table.to_s =~ /PRIMARY KEY\s+\((.+)\)/
528
+ if create_table.to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
529
529
  keys = $1.split(",").map { |key| key.gsub(/[`"]/, "") }
530
530
  keys.length == 1 ? [keys.first, nil] : nil
531
531
  else
@@ -264,7 +264,7 @@ module ActiveRecord
264
264
 
265
265
  # increase timeout so mysql server doesn't disconnect us
266
266
  wait_timeout = @config[:wait_timeout]
267
- wait_timeout = 2592000 unless wait_timeout.is_a?(Fixnum)
267
+ wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
268
268
  variable_assignments << "@@wait_timeout = #{wait_timeout}"
269
269
 
270
270
  execute("SET #{variable_assignments.join(', ')}", :skip_logging)
@@ -1067,14 +1067,25 @@ module ActiveRecord
1067
1067
 
1068
1068
  # Maps logical Rails types to PostgreSQL-specific data types.
1069
1069
  def type_to_sql(type, limit = nil, precision = nil, scale = nil)
1070
- return super unless type.to_s == 'integer'
1071
- return 'integer' unless limit
1072
-
1073
- case limit
1074
- when 1, 2; 'smallint'
1075
- when 3, 4; 'integer'
1076
- when 5..8; 'bigint'
1077
- else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
1070
+ case type.to_s
1071
+ when 'binary'
1072
+ # PostgreSQL doesn't support limits on binary (bytea) columns.
1073
+ # The hard limit is 1Gb, because of a 32-bit size field, and TOAST.
1074
+ case limit
1075
+ when nil, 0..0x3fffffff; super(type)
1076
+ else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
1077
+ end
1078
+ when 'integer'
1079
+ return 'integer' unless limit
1080
+
1081
+ case limit
1082
+ when 1, 2; 'smallint'
1083
+ when 3, 4; 'integer'
1084
+ when 5..8; 'bigint'
1085
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
1086
+ end
1087
+ else
1088
+ super
1078
1089
  end
1079
1090
  end
1080
1091
 
@@ -407,7 +407,14 @@ module ActiveRecord
407
407
 
408
408
  def remove_column(table_name, *column_names) #:nodoc:
409
409
  raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
410
- column_names.flatten.each do |column_name|
410
+
411
+ if column_names.flatten!
412
+ message = 'Passing array to remove_columns is deprecated, please use ' +
413
+ 'multiple arguments, like: `remove_columns(:posts, :foo, :bar)`'
414
+ ActiveSupport::Deprecation.warn message, caller
415
+ end
416
+
417
+ column_names.each do |column_name|
411
418
  alter_table(table_name) do |definition|
412
419
  definition.columns.delete(definition[column_name])
413
420
  end
@@ -419,11 +419,15 @@ module ActiveRecord
419
419
  cache_for_connection(connection).update(fixtures_map)
420
420
  end
421
421
 
422
- def self.instantiate_fixtures(object, fixture_name, fixtures, load_instances = true)
422
+ #--
423
+ # TODO:NOTE: in the next version, the __with_new_arity suffix and
424
+ # the method with the old arity will be removed.
425
+ #++
426
+ def self.instantiate_fixtures__with_new_arity(object, fixture_set, load_instances = true) # :nodoc:
423
427
  if load_instances
424
- fixtures.each do |name, fixture|
428
+ fixture_set.each do |fixture_name, fixture|
425
429
  begin
426
- object.instance_variable_set "@#{name}", fixture.find
430
+ object.instance_variable_set "@#{fixture_name}", fixture.find
427
431
  rescue FixtureClassNotFound
428
432
  nil
429
433
  end
@@ -431,9 +435,24 @@ module ActiveRecord
431
435
  end
432
436
  end
433
437
 
438
+ # The use with parameters <tt>(object, fixture_set_name, fixture_set, load_instances = true)</tt> is deprecated, +fixture_set_name+ parameter is not used.
439
+ # Use as:
440
+ #
441
+ # instantiate_fixtures(object, fixture_set, load_instances = true)
442
+ def self.instantiate_fixtures(object, fixture_set, load_instances = true, rails_3_2_compatibility_argument = true)
443
+ unless load_instances == true || load_instances == false
444
+ ActiveSupport::Deprecation.warn(
445
+ "ActiveRecord::Fixtures.instantiate_fixtures with parameters (object, fixture_set_name, fixture_set, load_instances = true) is deprecated and shall be removed from future releases. Use it with parameters (object, fixture_set, load_instances = true) instead (skip fixture_set_name).",
446
+ caller)
447
+ fixture_set = load_instances
448
+ load_instances = rails_3_2_compatibility_argument
449
+ end
450
+ instantiate_fixtures__with_new_arity(object, fixture_set, load_instances)
451
+ end
452
+
434
453
  def self.instantiate_all_loaded_fixtures(object, load_instances = true)
435
- all_loaded_fixtures.each do |table_name, fixtures|
436
- ActiveRecord::Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
454
+ all_loaded_fixtures.each_value do |fixture_set|
455
+ ActiveRecord::Fixtures.instantiate_fixtures(object, fixture_set, load_instances)
437
456
  end
438
457
  end
439
458
 
@@ -659,9 +678,6 @@ module ActiveRecord
659
678
  "#{@fixture_path}.yml"
660
679
  end
661
680
 
662
- def yaml_fixtures_key(path)
663
- ::File.basename(@fixture_path).split(".").first
664
- end
665
681
  end
666
682
 
667
683
  class Fixture #:nodoc:
@@ -893,8 +909,8 @@ module ActiveRecord
893
909
  ActiveRecord::Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
894
910
  else
895
911
  raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
896
- @loaded_fixtures.each do |fixture_name, fixtures|
897
- ActiveRecord::Fixtures.instantiate_fixtures(self, fixture_name, fixtures, load_instances?)
912
+ @loaded_fixtures.each_value do |fixture_set|
913
+ ActiveRecord::Fixtures.instantiate_fixtures(self, fixture_set, load_instances?)
898
914
  end
899
915
  end
900
916
  end
@@ -90,7 +90,7 @@ module ActiveRecord
90
90
  end
91
91
 
92
92
  def add(record)
93
- repository[record.class.symbolized_sti_name][record.id] = record
93
+ repository[record.class.symbolized_sti_name][record.id] = record if contain_all_columns?(record)
94
94
  end
95
95
 
96
96
  def remove(record)
@@ -104,6 +104,12 @@ module ActiveRecord
104
104
  def clear
105
105
  repository.clear
106
106
  end
107
+
108
+ private
109
+
110
+ def contain_all_columns?(record)
111
+ (record.class.column_names - record.attribute_names).empty?
112
+ end
107
113
  end
108
114
 
109
115
  # Reinitialize an Identity Map model object from +coder+.
@@ -63,15 +63,7 @@ module ActiveRecord
63
63
  record_id = sti_class.primary_key && record[sti_class.primary_key]
64
64
 
65
65
  if ActiveRecord::IdentityMap.enabled? && record_id
66
- if (column = sti_class.columns_hash[sti_class.primary_key]) && column.number?
67
- record_id = record_id.to_i
68
- end
69
- if instance = IdentityMap.get(sti_class, record_id)
70
- instance.reinit_with('attributes' => record)
71
- else
72
- instance = sti_class.allocate.init_with('attributes' => record)
73
- IdentityMap.add(instance)
74
- end
66
+ instance = use_identity_map(sti_class, record_id, record)
75
67
  else
76
68
  instance = sti_class.allocate.init_with('attributes' => record)
77
69
  end
@@ -122,6 +114,21 @@ module ActiveRecord
122
114
 
123
115
  private
124
116
 
117
+ def use_identity_map(sti_class, record_id, record)
118
+ if (column = sti_class.columns_hash[sti_class.primary_key]) && column.number?
119
+ record_id = record_id.to_i
120
+ end
121
+
122
+ if instance = IdentityMap.get(sti_class, record_id)
123
+ instance.reinit_with('attributes' => record)
124
+ else
125
+ instance = sti_class.allocate.init_with('attributes' => record)
126
+ IdentityMap.add(instance)
127
+ end
128
+
129
+ instance
130
+ end
131
+
125
132
  def find_sti_class(type_name)
126
133
  if type_name.blank? || !columns_hash.include?(inheritance_column)
127
134
  self
@@ -72,7 +72,13 @@ module ActiveRecord
72
72
  # and then establishes the connection.
73
73
  initializer "active_record.initialize_database" do |app|
74
74
  ActiveSupport.on_load(:active_record) do
75
- self.configurations = app.config.database_configuration
75
+ db_connection_type = "DATABASE_URL"
76
+ unless ENV['DATABASE_URL']
77
+ db_connection_type = "database.yml"
78
+ self.configurations = app.config.database_configuration
79
+ end
80
+ Rails.logger.info "Connecting to database specified by #{db_connection_type}"
81
+
76
82
  establish_connection
77
83
  end
78
84
  end
@@ -387,9 +387,9 @@ db_namespace = namespace :db do
387
387
  set_psql_env(abcs[Rails.env])
388
388
  search_path = abcs[Rails.env]['schema_search_path']
389
389
  unless search_path.blank?
390
- search_path = search_path.split(",").map{|search_path_part| "--schema=#{search_path_part.strip}" }.join(" ")
390
+ search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
391
391
  end
392
- `pg_dump -i -s -x -O -f #{filename} #{search_path} #{abcs[Rails.env]['database']}`
392
+ `pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(abcs[Rails.env]['database'])}`
393
393
  raise 'Error dumping database' if $?.exitstatus == 1
394
394
  when /sqlite/
395
395
  dbfile = abcs[Rails.env]['database']
@@ -403,6 +403,8 @@ module ActiveRecord
403
403
  # If you need to destroy dependent associations or call your <tt>before_*</tt> or
404
404
  # +after_destroy+ callbacks, use the +destroy_all+ method instead.
405
405
  def delete_all(conditions = nil)
406
+ raise ActiveRecordError.new("delete_all doesn't support limit scope") if self.limit_value
407
+
406
408
  IdentityMap.repository[symbolized_base_class] = {} if IdentityMap.enabled?
407
409
  if conditions
408
410
  where(conditions).delete_all
@@ -185,9 +185,8 @@ module ActiveRecord
185
185
  # Person.exists?(['name LIKE ?', "%#{query}%"])
186
186
  # Person.exists?
187
187
  def exists?(id = false)
188
- return false if id.nil?
189
-
190
188
  id = id.id if ActiveRecord::Base === id
189
+ return false if id.nil?
191
190
 
192
191
  join_dependency = construct_join_dependency_for_association_find
193
192
  relation = construct_relation_for_association_find(join_dependency)
@@ -34,7 +34,7 @@ module ActiveRecord
34
34
  if current_scope
35
35
  current_scope.clone
36
36
  else
37
- scope = relation.clone
37
+ scope = relation
38
38
  scope.default_scoped = true
39
39
  scope
40
40
  end
@@ -48,7 +48,7 @@ module ActiveRecord
48
48
  if current_scope
49
49
  current_scope.scope_for_create
50
50
  else
51
- scope = relation.clone
51
+ scope = relation
52
52
  scope.default_scoped = true
53
53
  scope.scope_for_create
54
54
  end
@@ -191,7 +191,7 @@ module ActiveRecord
191
191
  protected
192
192
 
193
193
  def valid_scope_name?(name)
194
- if respond_to?(name, true)
194
+ if logger && respond_to?(name, true)
195
195
  logger.warn "Creating scope :#{name}. " \
196
196
  "Overwriting existing method #{self.name}.#{name}."
197
197
  end
@@ -327,7 +327,8 @@ module ActiveRecord
327
327
  @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
328
328
  if @_start_transaction_state[:level] < 1
329
329
  restore_state = remove_instance_variable(:@_start_transaction_state)
330
- @attributes = @attributes.dup if @attributes.frozen?
330
+ was_frozen = @attributes.frozen?
331
+ @attributes = @attributes.dup if was_frozen
331
332
  @new_record = restore_state[:new_record]
332
333
  @destroyed = restore_state[:destroyed]
333
334
  if restore_state.has_key?(:id)
@@ -336,6 +337,7 @@ module ActiveRecord
336
337
  @attributes.delete(self.class.primary_key)
337
338
  @attributes_cache.delete(self.class.primary_key)
338
339
  end
340
+ @attributes.freeze if was_frozen
339
341
  end
340
342
  end
341
343
  end
@@ -54,13 +54,13 @@ module ActiveRecord
54
54
 
55
55
  def build_relation(klass, table, attribute, value) #:nodoc:
56
56
  column = klass.columns_hash[attribute.to_s]
57
- value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s if column.text?
57
+ value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s if value && column.text?
58
58
 
59
59
  if !options[:case_sensitive] && value && column.text?
60
60
  # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
61
61
  relation = klass.connection.case_insensitive_comparison(table, attribute, column, value)
62
62
  else
63
- value = klass.connection.case_sensitive_modifier(value)
63
+ value = klass.connection.case_sensitive_modifier(value) if value
64
64
  relation = table[attribute].eq(value)
65
65
  end
66
66
 
@@ -81,7 +81,7 @@ module ActiveRecord
81
81
  #
82
82
  # class Person < ActiveRecord::Base
83
83
  # validates_uniqueness_of :user_name, :scope => :account_id
84
- # end
84
+ # end
85
85
  #
86
86
  # Or even multiple scope parameters. For example, making sure that a teacher can only be on the schedule once
87
87
  # per semester for a particular class.
@@ -2,8 +2,8 @@ module ActiveRecord
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 2
5
- TINY = 3
6
- PRE = nil
5
+ TINY = 4
6
+ PRE = "rc1"
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
9
  end
@@ -13,9 +13,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration
13
13
  <% attributes.each do |attribute| -%>
14
14
  <%- if migration_action -%>
15
15
  <%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><%= attribute.inject_options %><% end %>
16
- <% if attribute.has_index? && migration_action == 'add' %>
16
+ <%- if attribute.has_index? && migration_action == 'add' -%>
17
17
  add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
18
- <% end -%>
18
+ <%- end -%>
19
19
  <%- end -%>
20
20
  <%- end -%>
21
21
  end
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
5
- prerelease: false
4
+ hash: -3869655734
5
+ prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
- - 3
10
- version: 3.2.3
9
+ - 4
10
+ - rc
11
+ - 1
12
+ version: 3.2.4.rc1
11
13
  platform: ruby
12
14
  authors:
13
15
  - David Heinemeier Hansson
@@ -15,43 +17,48 @@ autorequire:
15
17
  bindir: bin
16
18
  cert_chain: []
17
19
 
18
- date: 2012-03-30 00:00:00 -03:00
19
- default_executable:
20
+ date: 2012-05-28 00:00:00 Z
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
22
- version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ name: activesupport
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
23
26
  none: false
24
27
  requirements:
25
28
  - - "="
26
29
  - !ruby/object:Gem::Version
27
- hash: 9
30
+ hash: -3869655734
28
31
  segments:
29
32
  - 3
30
33
  - 2
31
- - 3
32
- version: 3.2.3
33
- requirement: *id001
34
+ - 4
35
+ - rc
36
+ - 1
37
+ version: 3.2.4.rc1
34
38
  type: :runtime
35
- name: activesupport
36
- prerelease: false
39
+ version_requirements: *id001
37
40
  - !ruby/object:Gem::Dependency
38
- version_requirements: &id002 !ruby/object:Gem::Requirement
41
+ name: activemodel
42
+ prerelease: false
43
+ requirement: &id002 !ruby/object:Gem::Requirement
39
44
  none: false
40
45
  requirements:
41
46
  - - "="
42
47
  - !ruby/object:Gem::Version
43
- hash: 9
48
+ hash: -3869655734
44
49
  segments:
45
50
  - 3
46
51
  - 2
47
- - 3
48
- version: 3.2.3
49
- requirement: *id002
52
+ - 4
53
+ - rc
54
+ - 1
55
+ version: 3.2.4.rc1
50
56
  type: :runtime
51
- name: activemodel
52
- prerelease: false
57
+ version_requirements: *id002
53
58
  - !ruby/object:Gem::Dependency
54
- version_requirements: &id003 !ruby/object:Gem::Requirement
59
+ name: arel
60
+ prerelease: false
61
+ requirement: &id003 !ruby/object:Gem::Requirement
55
62
  none: false
56
63
  requirements:
57
64
  - - ~>
@@ -62,12 +69,12 @@ dependencies:
62
69
  - 0
63
70
  - 2
64
71
  version: 3.0.2
65
- requirement: *id003
66
72
  type: :runtime
67
- name: arel
68
- prerelease: false
73
+ version_requirements: *id003
69
74
  - !ruby/object:Gem::Dependency
70
- version_requirements: &id004 !ruby/object:Gem::Requirement
75
+ name: tzinfo
76
+ prerelease: false
77
+ requirement: &id004 !ruby/object:Gem::Requirement
71
78
  none: false
72
79
  requirements:
73
80
  - - ~>
@@ -78,10 +85,8 @@ dependencies:
78
85
  - 3
79
86
  - 29
80
87
  version: 0.3.29
81
- requirement: *id004
82
88
  type: :runtime
83
- name: tzinfo
84
- prerelease: false
89
+ version_requirements: *id004
85
90
  description: Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes. Strong conventions for associations, validations, aggregations, migrations, and testing come baked-in.
86
91
  email: david@loudthinking.com
87
92
  executables: []
@@ -240,7 +245,6 @@ files:
240
245
  - lib/rails/generators/active_record/session_migration/session_migration_generator.rb
241
246
  - lib/rails/generators/active_record/session_migration/templates/migration.rb
242
247
  - lib/rails/generators/active_record.rb
243
- has_rdoc: true
244
248
  homepage: http://www.rubyonrails.org
245
249
  licenses: []
246
250
 
@@ -264,16 +268,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
264
268
  required_rubygems_version: !ruby/object:Gem::Requirement
265
269
  none: false
266
270
  requirements:
267
- - - ">="
271
+ - - ">"
268
272
  - !ruby/object:Gem::Version
269
- hash: 3
273
+ hash: 25
270
274
  segments:
271
- - 0
272
- version: "0"
275
+ - 1
276
+ - 3
277
+ - 1
278
+ version: 1.3.1
273
279
  requirements: []
274
280
 
275
281
  rubyforge_project:
276
- rubygems_version: 1.3.7
282
+ rubygems_version: 1.8.22
277
283
  signing_key:
278
284
  specification_version: 3
279
285
  summary: Object-relational mapper framework (part of Rails).