activerecord 3.1.9 → 3.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. checksums.yaml +6 -6
  2. data/CHANGELOG.md +317 -336
  3. data/README.rdoc +3 -3
  4. data/examples/performance.rb +20 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/associations/alias_tracker.rb +3 -6
  7. data/lib/active_record/associations/association.rb +3 -42
  8. data/lib/active_record/associations/association_scope.rb +3 -15
  9. data/lib/active_record/associations/builder/association.rb +6 -4
  10. data/lib/active_record/associations/builder/belongs_to.rb +3 -3
  11. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  12. data/lib/active_record/associations/builder/has_many.rb +4 -4
  13. data/lib/active_record/associations/builder/has_one.rb +5 -6
  14. data/lib/active_record/associations/builder/singular_association.rb +3 -16
  15. data/lib/active_record/associations/collection_association.rb +64 -31
  16. data/lib/active_record/associations/collection_proxy.rb +2 -37
  17. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -0
  18. data/lib/active_record/associations/has_many_association.rb +5 -1
  19. data/lib/active_record/associations/has_many_through_association.rb +28 -9
  20. data/lib/active_record/associations/has_one_association.rb +15 -13
  21. data/lib/active_record/associations/join_dependency.rb +2 -2
  22. data/lib/active_record/associations/preloader.rb +14 -10
  23. data/lib/active_record/associations/through_association.rb +7 -3
  24. data/lib/active_record/associations.rb +92 -76
  25. data/lib/active_record/attribute_assignment.rb +221 -0
  26. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  27. data/lib/active_record/attribute_methods/dirty.rb +21 -11
  28. data/lib/active_record/attribute_methods/primary_key.rb +62 -25
  29. data/lib/active_record/attribute_methods/read.rb +73 -83
  30. data/lib/active_record/attribute_methods/serialization.rb +102 -0
  31. data/lib/active_record/attribute_methods/time_zone_conversion.rb +23 -17
  32. data/lib/active_record/attribute_methods/write.rb +31 -6
  33. data/lib/active_record/attribute_methods.rb +231 -30
  34. data/lib/active_record/autosave_association.rb +43 -22
  35. data/lib/active_record/base.rb +227 -1708
  36. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +150 -148
  37. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +85 -29
  38. data/lib/active_record/connection_adapters/abstract/database_statements.rb +6 -33
  39. data/lib/active_record/connection_adapters/abstract/query_cache.rb +10 -2
  40. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -6
  41. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -26
  42. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -19
  43. data/lib/active_record/connection_adapters/abstract_adapter.rb +77 -42
  44. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +674 -0
  45. data/lib/active_record/connection_adapters/column.rb +37 -11
  46. data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -581
  47. data/lib/active_record/connection_adapters/mysql_adapter.rb +137 -696
  48. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -86
  49. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  50. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
  51. data/lib/active_record/connection_adapters/sqlite_adapter.rb +55 -32
  52. data/lib/active_record/counter_cache.rb +9 -4
  53. data/lib/active_record/dynamic_finder_match.rb +12 -0
  54. data/lib/active_record/dynamic_matchers.rb +84 -0
  55. data/lib/active_record/errors.rb +11 -1
  56. data/lib/active_record/explain.rb +85 -0
  57. data/lib/active_record/explain_subscriber.rb +25 -0
  58. data/lib/active_record/fixtures/file.rb +65 -0
  59. data/lib/active_record/fixtures.rb +56 -85
  60. data/lib/active_record/identity_map.rb +3 -4
  61. data/lib/active_record/inheritance.rb +174 -0
  62. data/lib/active_record/integration.rb +49 -0
  63. data/lib/active_record/locking/optimistic.rb +30 -25
  64. data/lib/active_record/locking/pessimistic.rb +23 -1
  65. data/lib/active_record/log_subscriber.rb +3 -3
  66. data/lib/active_record/migration/command_recorder.rb +8 -8
  67. data/lib/active_record/migration.rb +68 -35
  68. data/lib/active_record/model_schema.rb +366 -0
  69. data/lib/active_record/nested_attributes.rb +3 -2
  70. data/lib/active_record/persistence.rb +57 -11
  71. data/lib/active_record/querying.rb +58 -0
  72. data/lib/active_record/railtie.rb +31 -29
  73. data/lib/active_record/railties/controller_runtime.rb +3 -1
  74. data/lib/active_record/railties/databases.rake +191 -110
  75. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  76. data/lib/active_record/readonly_attributes.rb +26 -0
  77. data/lib/active_record/reflection.rb +7 -15
  78. data/lib/active_record/relation/batches.rb +5 -2
  79. data/lib/active_record/relation/calculations.rb +47 -15
  80. data/lib/active_record/relation/delegation.rb +49 -0
  81. data/lib/active_record/relation/finder_methods.rb +9 -7
  82. data/lib/active_record/relation/predicate_builder.rb +18 -7
  83. data/lib/active_record/relation/query_methods.rb +75 -9
  84. data/lib/active_record/relation/spawn_methods.rb +11 -2
  85. data/lib/active_record/relation.rb +78 -32
  86. data/lib/active_record/result.rb +1 -1
  87. data/lib/active_record/sanitization.rb +194 -0
  88. data/lib/active_record/schema_dumper.rb +12 -5
  89. data/lib/active_record/scoping/default.rb +142 -0
  90. data/lib/active_record/scoping/named.rb +202 -0
  91. data/lib/active_record/scoping.rb +152 -0
  92. data/lib/active_record/serialization.rb +1 -43
  93. data/lib/active_record/serializers/xml_serializer.rb +4 -45
  94. data/lib/active_record/session_store.rb +17 -15
  95. data/lib/active_record/store.rb +52 -0
  96. data/lib/active_record/test_case.rb +11 -7
  97. data/lib/active_record/timestamp.rb +17 -3
  98. data/lib/active_record/transactions.rb +27 -6
  99. data/lib/active_record/translation.rb +22 -0
  100. data/lib/active_record/validations/associated.rb +5 -4
  101. data/lib/active_record/validations/uniqueness.rb +7 -7
  102. data/lib/active_record/validations.rb +1 -1
  103. data/lib/active_record/version.rb +2 -2
  104. data/lib/active_record.rb +38 -3
  105. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  106. data/lib/rails/generators/active_record/migration/templates/migration.rb +12 -3
  107. data/lib/rails/generators/active_record/model/model_generator.rb +9 -1
  108. data/lib/rails/generators/active_record/model/templates/migration.rb +3 -5
  109. data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
  110. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
  111. metadata +30 -10
  112. data/lib/active_record/named_scope.rb +0 -200
@@ -8,7 +8,9 @@ module ActiveRecord
8
8
 
9
9
  def initialize(owner, reflection)
10
10
  super
11
- @through_records = {}
11
+
12
+ @through_records = {}
13
+ @through_association = nil
12
14
  end
13
15
 
14
16
  # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been
@@ -36,6 +38,20 @@ module ActiveRecord
36
38
  super
37
39
  end
38
40
 
41
+ def concat_records(records)
42
+ ensure_not_nested
43
+
44
+ records = super
45
+
46
+ if owner.new_record? && records
47
+ records.flatten.each do |record|
48
+ build_through_record(record)
49
+ end
50
+ end
51
+
52
+ records
53
+ end
54
+
39
55
  def insert_record(record, validate = true, raise = false)
40
56
  ensure_not_nested
41
57
 
@@ -59,7 +75,7 @@ module ActiveRecord
59
75
  private
60
76
 
61
77
  def through_association
62
- owner.association(through_reflection.name)
78
+ @through_association ||= owner.association(through_reflection.name)
63
79
  end
64
80
 
65
81
  # We temporarily cache through record that has been build, because if we build a
@@ -71,7 +87,9 @@ module ActiveRecord
71
87
  # association
72
88
  def build_through_record(record)
73
89
  @through_records[record.object_id] ||= begin
74
- through_record = through_association.build(construct_join_attributes(record))
90
+ ensure_mutable
91
+
92
+ through_record = through_association.build
75
93
  through_record.send("#{source_reflection.name}=", record)
76
94
  through_record
77
95
  end
@@ -122,8 +140,7 @@ module ActiveRecord
122
140
  def delete_records(records, method)
123
141
  ensure_not_nested
124
142
 
125
- through = through_association
126
- scope = through.scoped.where(construct_join_attributes(*records))
143
+ scope = through_association.scoped.where(construct_join_attributes(*records))
127
144
 
128
145
  case method
129
146
  when :destroy
@@ -134,7 +151,7 @@ module ActiveRecord
134
151
  count = scope.delete_all
135
152
  end
136
153
 
137
- delete_through_records(through, records)
154
+ delete_through_records(records)
138
155
 
139
156
  if through_reflection.macro == :has_many && update_through_counter?(method)
140
157
  update_counter(-count, through_reflection)
@@ -149,14 +166,16 @@ module ActiveRecord
149
166
  candidates.find_all { |c| c.attributes.slice(*attributes.keys) == attributes }
150
167
  end
151
168
 
152
- def delete_through_records(through, records)
169
+ def delete_through_records(records)
153
170
  records.each do |record|
154
171
  through_records = through_records_for(record)
155
172
 
156
173
  if through_reflection.macro == :has_many
157
- through_records.each { |r| through.target.delete(r) }
174
+ through_records.each { |r| through_association.target.delete(r) }
158
175
  else
159
- through.target = nil if through_records.include?(through.target)
176
+ if through_records.include?(through_association.target)
177
+ through_association.target = nil
178
+ end
160
179
  end
161
180
 
162
181
  @through_records.delete(record.object_id)
@@ -8,19 +8,21 @@ module ActiveRecord
8
8
  raise_on_type_mismatch(record) if record
9
9
  load_target
10
10
 
11
- reflection.klass.transaction do
12
- if target && target != record
13
- remove_target!(options[:dependent]) unless target.destroyed?
14
- end
15
-
16
- if record
17
- set_owner_attributes(record)
18
- set_inverse_instance(record)
19
-
20
- if owner.persisted? && save && !record.save
21
- nullify_owner_attributes(record)
22
- set_owner_attributes(target) if target
23
- raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
11
+ # If target and record are nil, or target is equal to record,
12
+ # we don't need to have transaction.
13
+ if (target || record) && target != record
14
+ reflection.klass.transaction do
15
+ remove_target!(options[:dependent]) if target && !target.destroyed?
16
+
17
+ if record
18
+ set_owner_attributes(record)
19
+ set_inverse_instance(record)
20
+
21
+ if owner.persisted? && save && !record.save
22
+ nullify_owner_attributes(record)
23
+ set_owner_attributes(target) if target
24
+ raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
25
+ end
24
26
  end
25
27
  end
26
28
  end
@@ -13,7 +13,7 @@ module ActiveRecord
13
13
  @join_parts = [JoinBase.new(base)]
14
14
  @associations = {}
15
15
  @reflections = []
16
- @alias_tracker = AliasTracker.new(joins)
16
+ @alias_tracker = AliasTracker.new(base.connection, joins)
17
17
  @alias_tracker.aliased_name_for(base.table_name) # Updates the count for base.table_name to 1
18
18
  build(associations)
19
19
  end
@@ -184,7 +184,7 @@ module ActiveRecord
184
184
 
185
185
  macro = join_part.reflection.macro
186
186
  if macro == :has_one
187
- return if record.association_cache.key?(join_part.reflection.name)
187
+ return record.association(join_part.reflection.name).target if record.association_cache.key?(join_part.reflection.name)
188
188
  association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil?
189
189
  set_target_and_inverse(join_part, association, record)
190
190
  else
@@ -30,17 +30,21 @@ module ActiveRecord
30
30
  # option references an association's column), it will fallback to the table
31
31
  # join strategy.
32
32
  class Preloader #:nodoc:
33
- autoload :Association, 'active_record/associations/preloader/association'
34
- autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
35
- autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
36
- autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
33
+ extend ActiveSupport::Autoload
37
34
 
38
- autoload :HasMany, 'active_record/associations/preloader/has_many'
39
- autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
40
- autoload :HasOne, 'active_record/associations/preloader/has_one'
41
- autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
42
- autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
43
- autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
35
+ eager_autoload do
36
+ autoload :Association, 'active_record/associations/preloader/association'
37
+ autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
38
+ autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
39
+ autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
40
+
41
+ autoload :HasMany, 'active_record/associations/preloader/has_many'
42
+ autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
43
+ autoload :HasOne, 'active_record/associations/preloader/has_one'
44
+ autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
45
+ autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
46
+ autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
47
+ end
44
48
 
45
49
  attr_reader :records, :associations, :options, :model
46
50
 
@@ -37,9 +37,7 @@ module ActiveRecord
37
37
  # situation it is more natural for the user to just create or modify their join records
38
38
  # directly as required.
39
39
  def construct_join_attributes(*records)
40
- if source_reflection.macro != :belongs_to
41
- raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection)
42
- end
40
+ ensure_mutable
43
41
 
44
42
  join_attributes = {
45
43
  source_reflection.foreign_key =>
@@ -73,6 +71,12 @@ module ActiveRecord
73
71
  !owner[through_reflection.foreign_key].nil?
74
72
  end
75
73
 
74
+ def ensure_mutable
75
+ if source_reflection.macro != :belongs_to
76
+ raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection)
77
+ end
78
+ end
79
+
76
80
  def ensure_not_nested
77
81
  if reflection.nested?
78
82
  raise HasManyThroughNestedAssociationsAreReadonly.new(owner, reflection)