activerecord 4.1.16 → 4.2.0.beta1

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

Potentially problematic release.


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

Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +634 -2185
  3. data/README.rdoc +15 -10
  4. data/lib/active_record.rb +2 -1
  5. data/lib/active_record/aggregations.rb +12 -8
  6. data/lib/active_record/associations.rb +58 -33
  7. data/lib/active_record/associations/association.rb +1 -1
  8. data/lib/active_record/associations/association_scope.rb +53 -21
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  10. data/lib/active_record/associations/builder/association.rb +16 -5
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
  13. data/lib/active_record/associations/builder/has_one.rb +2 -2
  14. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  15. data/lib/active_record/associations/collection_association.rb +32 -44
  16. data/lib/active_record/associations/collection_proxy.rb +1 -10
  17. data/lib/active_record/associations/has_many_association.rb +60 -14
  18. data/lib/active_record/associations/has_many_through_association.rb +34 -23
  19. data/lib/active_record/associations/has_one_association.rb +0 -1
  20. data/lib/active_record/associations/join_dependency.rb +7 -9
  21. data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
  22. data/lib/active_record/associations/preloader.rb +2 -2
  23. data/lib/active_record/associations/preloader/association.rb +9 -5
  24. data/lib/active_record/associations/preloader/through_association.rb +3 -3
  25. data/lib/active_record/associations/singular_association.rb +16 -1
  26. data/lib/active_record/associations/through_association.rb +6 -22
  27. data/lib/active_record/attribute.rb +131 -0
  28. data/lib/active_record/attribute_assignment.rb +19 -11
  29. data/lib/active_record/attribute_decorators.rb +66 -0
  30. data/lib/active_record/attribute_methods.rb +53 -90
  31. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  32. data/lib/active_record/attribute_methods/dirty.rb +85 -42
  33. data/lib/active_record/attribute_methods/primary_key.rb +6 -8
  34. data/lib/active_record/attribute_methods/read.rb +14 -57
  35. data/lib/active_record/attribute_methods/serialization.rb +12 -146
  36. data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
  37. data/lib/active_record/attribute_methods/write.rb +8 -23
  38. data/lib/active_record/attribute_set.rb +77 -0
  39. data/lib/active_record/attribute_set/builder.rb +32 -0
  40. data/lib/active_record/attributes.rb +122 -0
  41. data/lib/active_record/autosave_association.rb +11 -21
  42. data/lib/active_record/base.rb +9 -19
  43. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
  44. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
  45. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
  46. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
  47. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
  48. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
  49. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
  50. data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
  51. data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
  52. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
  53. data/lib/active_record/connection_adapters/column.rb +13 -244
  54. data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
  55. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
  56. data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
  57. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  58. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  59. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
  60. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
  62. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  64. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  66. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  67. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  86. data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
  87. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  88. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
  89. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
  90. data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
  91. data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
  92. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  93. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
  94. data/lib/active_record/connection_handling.rb +1 -1
  95. data/lib/active_record/core.rb +119 -22
  96. data/lib/active_record/counter_cache.rb +60 -6
  97. data/lib/active_record/enum.rb +9 -10
  98. data/lib/active_record/errors.rb +27 -26
  99. data/lib/active_record/explain.rb +1 -1
  100. data/lib/active_record/fixtures.rb +52 -45
  101. data/lib/active_record/gem_version.rb +3 -3
  102. data/lib/active_record/inheritance.rb +33 -8
  103. data/lib/active_record/integration.rb +4 -4
  104. data/lib/active_record/locking/optimistic.rb +34 -16
  105. data/lib/active_record/migration.rb +22 -32
  106. data/lib/active_record/migration/command_recorder.rb +19 -2
  107. data/lib/active_record/migration/join_table.rb +1 -1
  108. data/lib/active_record/model_schema.rb +39 -48
  109. data/lib/active_record/nested_attributes.rb +8 -18
  110. data/lib/active_record/persistence.rb +39 -22
  111. data/lib/active_record/query_cache.rb +3 -3
  112. data/lib/active_record/querying.rb +1 -8
  113. data/lib/active_record/railtie.rb +17 -10
  114. data/lib/active_record/railties/databases.rake +47 -42
  115. data/lib/active_record/readonly_attributes.rb +0 -1
  116. data/lib/active_record/reflection.rb +225 -92
  117. data/lib/active_record/relation.rb +35 -11
  118. data/lib/active_record/relation/batches.rb +0 -2
  119. data/lib/active_record/relation/calculations.rb +28 -32
  120. data/lib/active_record/relation/delegation.rb +1 -1
  121. data/lib/active_record/relation/finder_methods.rb +42 -20
  122. data/lib/active_record/relation/merger.rb +0 -1
  123. data/lib/active_record/relation/predicate_builder.rb +1 -22
  124. data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
  125. data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
  126. data/lib/active_record/relation/query_methods.rb +98 -62
  127. data/lib/active_record/relation/spawn_methods.rb +6 -7
  128. data/lib/active_record/result.rb +16 -9
  129. data/lib/active_record/sanitization.rb +8 -1
  130. data/lib/active_record/schema.rb +0 -1
  131. data/lib/active_record/schema_dumper.rb +51 -9
  132. data/lib/active_record/schema_migration.rb +4 -0
  133. data/lib/active_record/scoping/default.rb +5 -4
  134. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  135. data/lib/active_record/statement_cache.rb +79 -5
  136. data/lib/active_record/store.rb +5 -5
  137. data/lib/active_record/tasks/database_tasks.rb +37 -5
  138. data/lib/active_record/tasks/mysql_database_tasks.rb +10 -16
  139. data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
  140. data/lib/active_record/timestamp.rb +9 -7
  141. data/lib/active_record/transactions.rb +35 -21
  142. data/lib/active_record/type.rb +20 -0
  143. data/lib/active_record/type/binary.rb +40 -0
  144. data/lib/active_record/type/boolean.rb +19 -0
  145. data/lib/active_record/type/date.rb +46 -0
  146. data/lib/active_record/type/date_time.rb +43 -0
  147. data/lib/active_record/type/decimal.rb +40 -0
  148. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  149. data/lib/active_record/type/float.rb +19 -0
  150. data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
  151. data/lib/active_record/type/integer.rb +23 -0
  152. data/lib/active_record/type/mutable.rb +16 -0
  153. data/lib/active_record/type/numeric.rb +36 -0
  154. data/lib/active_record/type/serialized.rb +51 -0
  155. data/lib/active_record/type/string.rb +36 -0
  156. data/lib/active_record/type/text.rb +11 -0
  157. data/lib/active_record/type/time.rb +26 -0
  158. data/lib/active_record/type/time_value.rb +38 -0
  159. data/lib/active_record/type/type_map.rb +48 -0
  160. data/lib/active_record/type/value.rb +101 -0
  161. data/lib/active_record/validations.rb +21 -16
  162. data/lib/active_record/validations/uniqueness.rb +9 -23
  163. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  164. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  165. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  166. metadata +71 -14
  167. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  # ==== Parameters
12
12
  #
13
13
  # * +id+ - The id of the object you wish to reset a counter on.
14
- # * +counters+ - One or more association counters to reset
14
+ # * +counters+ - One or more association counters to reset. Association name or counter name can be given.
15
15
  #
16
16
  # ==== Examples
17
17
  #
@@ -19,9 +19,14 @@ module ActiveRecord
19
19
  # Post.reset_counters(1, :comments)
20
20
  def reset_counters(id, *counters)
21
21
  object = find(id)
22
- counters.each do |association|
23
- has_many_association = _reflect_on_association(association.to_sym)
24
- raise ArgumentError, "'#{self.name}' has no association called '#{association}'" unless has_many_association
22
+ counters.each do |counter_association|
23
+ has_many_association = _reflect_on_association(counter_association.to_sym)
24
+ unless has_many_association
25
+ has_many = reflect_on_all_associations(:has_many)
26
+ has_many_association = has_many.find { |association| association.counter_cache_column && association.counter_cache_column.to_sym == counter_association.to_sym }
27
+ counter_association = has_many_association.plural_name if has_many_association
28
+ end
29
+ raise ArgumentError, "'#{self.name}' has no association called '#{counter_association}'" unless has_many_association
25
30
 
26
31
  if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
27
32
  has_many_association = has_many_association.through_reflection
@@ -29,11 +34,11 @@ module ActiveRecord
29
34
 
30
35
  foreign_key = has_many_association.foreign_key.to_s
31
36
  child_class = has_many_association.klass
32
- reflection = child_class._reflections.values.find { |e| :belongs_to == e.macro && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
37
+ reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
33
38
  counter_name = reflection.counter_cache_column
34
39
 
35
40
  stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
36
- arel_table[counter_name] => object.send(association).count(:all)
41
+ arel_table[counter_name] => object.send(counter_association).count(:all)
37
42
  }, primary_key)
38
43
  connection.update stmt
39
44
  end
@@ -117,5 +122,54 @@ module ActiveRecord
117
122
  update_counters(id, counter_name => -1)
118
123
  end
119
124
  end
125
+
126
+ protected
127
+
128
+ def actually_destroyed?
129
+ @_actually_destroyed
130
+ end
131
+
132
+ def clear_destroy_state
133
+ @_actually_destroyed = nil
134
+ end
135
+
136
+ private
137
+
138
+ def _create_record(*)
139
+ id = super
140
+
141
+ each_counter_cached_associations do |association|
142
+ if send(association.reflection.name)
143
+ association.increment_counters
144
+ @_after_create_counter_called = true
145
+ end
146
+ end
147
+
148
+ id
149
+ end
150
+
151
+ def destroy_row
152
+ affected_rows = super
153
+
154
+ if affected_rows > 0
155
+ each_counter_cached_associations do |association|
156
+ foreign_key = association.reflection.foreign_key.to_sym
157
+ unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
158
+ if send(association.reflection.name)
159
+ association.decrement_counters
160
+ end
161
+ end
162
+ end
163
+ end
164
+
165
+ affected_rows
166
+ end
167
+
168
+ def each_counter_cached_associations
169
+ _reflections.each do |name, reflection|
170
+ yield association(name) if reflection.belongs_to? && reflection.counter_cache_column
171
+ end
172
+ end
173
+
120
174
  end
121
175
  end
@@ -27,8 +27,10 @@ module ActiveRecord
27
27
  # conversation.status # => nil
28
28
  #
29
29
  # Scopes based on the allowed values of the enum field will be provided
30
- # as well. With the above example, it will create an +active+ and +archived+
31
- # scope.
30
+ # as well. With the above example:
31
+ #
32
+ # Conversation.active
33
+ # Conversation.archived
32
34
  #
33
35
  # You can set the default value from the database declaration, like:
34
36
  #
@@ -68,7 +70,7 @@ module ActiveRecord
68
70
  # Where conditions on an enum attribute must use the ordinal value of an enum.
69
71
  module Enum
70
72
  def self.extended(base) # :nodoc:
71
- base.class_attribute(:defined_enums, instance_writer: false)
73
+ base.class_attribute(:defined_enums)
72
74
  base.defined_enums = {}
73
75
  end
74
76
 
@@ -138,19 +140,16 @@ module ActiveRecord
138
140
  @_enum_methods_module ||= begin
139
141
  mod = Module.new do
140
142
  private
141
- def save_changed_attribute(attr_name, value)
143
+ def save_changed_attribute(attr_name, old)
142
144
  if (mapping = self.class.defined_enums[attr_name.to_s])
145
+ value = read_attribute(attr_name)
143
146
  if attribute_changed?(attr_name)
144
- old = changed_attributes[attr_name]
145
-
146
147
  if mapping[old] == value
147
- changed_attributes.delete(attr_name)
148
+ clear_attribute_changes([attr_name])
148
149
  end
149
150
  else
150
- old = clone_attribute_value(:read_attribute, attr_name)
151
-
152
151
  if old != value
153
- changed_attributes[attr_name] = mapping.key old
152
+ set_attribute_was(attr_name, mapping.key(old))
154
153
  end
155
154
  end
156
155
  else
@@ -30,17 +30,18 @@ module ActiveRecord
30
30
  class SerializationTypeMismatch < ActiveRecordError
31
31
  end
32
32
 
33
- # Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt>
34
- # misses adapter field).
33
+ # Raised when adapter not specified on connection (or configuration file
34
+ # +config/database.yml+ misses adapter field).
35
35
  class AdapterNotSpecified < ActiveRecordError
36
36
  end
37
37
 
38
- # Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically.
38
+ # Raised when Active Record cannot find database adapter specified in
39
+ # +config/database.yml+ or programmatically.
39
40
  class AdapterNotFound < ActiveRecordError
40
41
  end
41
42
 
42
- # Raised when connection to the database could not been established (for example when <tt>connection=</tt>
43
- # is given a nil object).
43
+ # Raised when connection to the database could not been established (for
44
+ # example when +connection=+ is given a nil object).
44
45
  class ConnectionNotEstablished < ActiveRecordError
45
46
  end
46
47
 
@@ -82,35 +83,26 @@ module ActiveRecord
82
83
  class InvalidForeignKey < WrappedDatabaseException
83
84
  end
84
85
 
85
- # Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example,
86
- # when using +find+ method)
87
- # does not match number of expected variables.
86
+ # Raised when number of bind variables in statement given to +:condition+ key
87
+ # (for example, when using +find+ method) does not match number of expected
88
+ # values supplied.
88
89
  #
89
- # For example, in
90
+ # For example, when there are two placeholders with only one value supplied:
90
91
  #
91
92
  # Location.where("lat = ? AND lng = ?", 53.7362)
92
- #
93
- # two placeholders are given but only one variable to fill them.
94
93
  class PreparedStatementInvalid < ActiveRecordError
95
94
  end
96
95
 
97
- # Raised when a given database does not exist
98
- class NoDatabaseError < ActiveRecordError
99
- def initialize(message)
100
- super extend_message(message)
101
- end
102
-
103
- # can be over written to add additional error information.
104
- def extend_message(message)
105
- message
106
- end
96
+ # Raised when a given database does not exist.
97
+ class NoDatabaseError < StatementInvalid
107
98
  end
108
99
 
109
100
  # Raised on attempt to save stale record. Record is stale when it's being saved in another query after
110
101
  # instantiation, for example, when two users edit the same wiki page and one starts editing and saves
111
102
  # the page before the other.
112
103
  #
113
- # Read more about optimistic locking in ActiveRecord::Locking module RDoc.
104
+ # Read more about optimistic locking in ActiveRecord::Locking module
105
+ # documentation.
114
106
  class StaleObjectError < ActiveRecordError
115
107
  attr_reader :record, :attempted_action
116
108
 
@@ -122,8 +114,9 @@ module ActiveRecord
122
114
 
123
115
  end
124
116
 
125
- # Raised when association is being configured improperly or
126
- # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.
117
+ # Raised when association is being configured improperly or user tries to use
118
+ # offset and limit together with +has_many+ or +has_and_belongs_to_many+
119
+ # associations.
127
120
  class ConfigurationError < ActiveRecordError
128
121
  end
129
122
 
@@ -161,7 +154,8 @@ module ActiveRecord
161
154
  class Rollback < ActiveRecordError
162
155
  end
163
156
 
164
- # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods).
157
+ # Raised when attribute has a name reserved by Active Record (when attribute
158
+ # has name of one of Active Record instance methods).
165
159
  class DangerousAttributeError < ActiveRecordError
166
160
  end
167
161
 
@@ -179,7 +173,7 @@ module ActiveRecord
179
173
  end
180
174
 
181
175
  # Raised when an error occurred while doing a mass assignment to an attribute through the
182
- # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
176
+ # +attributes=+ method. The exception has an +attribute+ property that is the name of the
183
177
  # offending attribute.
184
178
  class AttributeAssignmentError < ActiveRecordError
185
179
  attr_reader :exception, :attribute
@@ -225,6 +219,13 @@ module ActiveRecord
225
219
  class ImmutableRelation < ActiveRecordError
226
220
  end
227
221
 
222
+ # TransactionIsolationError will be raised under the following conditions:
223
+ #
224
+ # * The adapter does not support setting the isolation level
225
+ # * You are joining an existing open transaction
226
+ # * You are creating a nested (savepoint) transaction
227
+ #
228
+ # The mysql, mysql2 and postgresql adapters support setting the transaction isolation level.
228
229
  class TransactionIsolationError < ActiveRecordError
229
230
  end
230
231
  end
@@ -27,7 +27,7 @@ module ActiveRecord
27
27
  end.join("\n")
28
28
  end.join("\n")
29
29
 
30
- # Overriding inspect to be more human readable, specially in the console.
30
+ # Overriding inspect to be more human readable, especially in the console.
31
31
  def str.inspect
32
32
  self
33
33
  end
@@ -2,6 +2,7 @@ require 'erb'
2
2
  require 'yaml'
3
3
  require 'zlib'
4
4
  require 'active_support/dependencies'
5
+ require 'active_support/core_ext/digest/uuid'
5
6
  require 'active_record/fixture_set/file'
6
7
  require 'active_record/errors'
7
8
 
@@ -14,9 +15,10 @@ module ActiveRecord
14
15
  # They are stored in YAML files, one file per model, which are placed in the directory
15
16
  # appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
16
17
  # configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
17
- # The fixture file ends with the <tt>.yml</tt> file extension (Rails example:
18
- # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). The format of a fixture file looks
19
- # like this:
18
+ # The fixture file ends with the +.yml+ file extension, for example:
19
+ # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
20
+ #
21
+ # The format of a fixture file looks like this:
20
22
  #
21
23
  # rubyonrails:
22
24
  # id: 1
@@ -32,7 +34,7 @@ module ActiveRecord
32
34
  # is followed by an indented list of key/value pairs in the "key: value" format. Records are
33
35
  # separated by a blank line for your viewing pleasure.
34
36
  #
35
- # Note that fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
37
+ # Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
36
38
  # See http://yaml.org/type/omap.html
37
39
  # for the specification. You will need ordered fixtures when you have foreign key constraints
38
40
  # on keys in the same table. This is commonly needed for tree structures. Example:
@@ -60,8 +62,8 @@ module ActiveRecord
60
62
  # end
61
63
  # end
62
64
  #
63
- # By default, <tt>test_helper.rb</tt> will load all of your fixtures into your test database,
64
- # so this test will succeed.
65
+ # By default, +test_helper.rb+ will load all of your fixtures into your test
66
+ # database, so this test will succeed.
65
67
  #
66
68
  # The testing environment will automatically load the all fixtures into the database before each
67
69
  # test. To ensure consistent data, the environment deletes the fixtures before running the load.
@@ -124,7 +126,7 @@ module ActiveRecord
124
126
  # that is included in <tt>ActiveRecord::FixtureSet.context_class</tt>.
125
127
  #
126
128
  # - define a helper method in `test_helper.rb`
127
- # module FixtureFileHelpers
129
+ # class FixtureFileHelpers
128
130
  # def file_sha(path)
129
131
  # Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
130
132
  # end
@@ -361,6 +363,7 @@ module ActiveRecord
361
363
  # geeksomnia:
362
364
  # name: Geeksomnia's Account
363
365
  # subdomain: $LABEL
366
+ # email: $LABEL@email.com
364
367
  #
365
368
  # Also, sometimes (like when porting older join table fixtures) you'll need
366
369
  # to be able to get a hold of the identifier for a given label. ERB
@@ -372,8 +375,9 @@ module ActiveRecord
372
375
  #
373
376
  # == Support for YAML defaults
374
377
  #
375
- # You probably already know how to use YAML to set and reuse defaults in
376
- # your <tt>database.yml</tt> file. You can use the same technique in your fixtures:
378
+ # You can set and reuse defaults in your fixtures YAML file.
379
+ # This is the same technique used in the +database.yml+ file to specify
380
+ # defaults:
377
381
  #
378
382
  # DEFAULTS: &DEFAULTS
379
383
  # created_on: <%= 3.weeks.ago.to_s(:db) %>
@@ -389,7 +393,8 @@ module ActiveRecord
389
393
  # Any fixture labeled "DEFAULTS" is safely ignored.
390
394
  class FixtureSet
391
395
  #--
392
- # An instance of FixtureSet is normally stored in a single YAML file and possibly in a folder with the same name.
396
+ # An instance of FixtureSet is normally stored in a single YAML file and
397
+ # possibly in a folder with the same name.
393
398
  #++
394
399
 
395
400
  MAX_ID = 2 ** 30 - 1
@@ -459,13 +464,7 @@ module ActiveRecord
459
464
  @config = config
460
465
 
461
466
  # Remove string values that aren't constants or subclasses of AR
462
- @class_names.delete_if { |k,klass|
463
- unless klass.is_a? Class
464
- klass = klass.safe_constantize
465
- ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `set_fixture_class` will be removed in Rails 4.2. Use the class itself instead.")
466
- end
467
- !insert_class(@class_names, k, klass)
468
- }
467
+ @class_names.delete_if { |klass_name, klass| !insert_class(@class_names, klass_name, klass) }
469
468
  end
470
469
 
471
470
  def [](fs_name)
@@ -532,10 +531,12 @@ module ActiveRecord
532
531
  conn.insert_fixture(row, fixture_set_name)
533
532
  end
534
533
  end
534
+ end
535
535
 
536
- # Cap primary key sequences to max(pk).
537
- if conn.respond_to?(:reset_pk_sequence!)
538
- conn.reset_pk_sequence!(fs.table_name)
536
+ # Cap primary key sequences to max(pk).
537
+ if connection.respond_to?(:reset_pk_sequence!)
538
+ fixture_sets.each do |fs|
539
+ connection.reset_pk_sequence!(fs.table_name)
539
540
  end
540
541
  end
541
542
  end
@@ -547,9 +548,13 @@ module ActiveRecord
547
548
  end
548
549
 
549
550
  # Returns a consistent, platform-independent identifier for +label+.
550
- # Identifiers are positive integers less than 2^32.
551
- def self.identify(label)
552
- Zlib.crc32(label.to_s) % MAX_ID
551
+ # Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
552
+ def self.identify(label, column_type = :integer)
553
+ if column_type == :uuid
554
+ Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
555
+ else
556
+ Zlib.crc32(label.to_s) % MAX_ID
557
+ end
553
558
  end
554
559
 
555
560
  # Superclass for the evaluation contexts used by ERB fixtures.
@@ -565,10 +570,6 @@ module ActiveRecord
565
570
  @config = config
566
571
  @model_class = nil
567
572
 
568
- if class_name.is_a?(String)
569
- ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `FixtureSet.new` will be removed in Rails 4.2. Use the class itself instead.")
570
- end
571
-
572
573
  if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
573
574
  @model_class = class_name
574
575
  else
@@ -625,12 +626,12 @@ module ActiveRecord
625
626
 
626
627
  # interpolate the fixture label
627
628
  row.each do |key, value|
628
- row[key] = label if "$LABEL" == value
629
+ row[key] = value.gsub("$LABEL", label) if value.is_a?(String)
629
630
  end
630
631
 
631
632
  # generate a primary key if necessary
632
633
  if has_primary_key_column? && !row.include?(primary_key_name)
633
- row[primary_key_name] = ActiveRecord::FixtureSet.identify(label)
634
+ row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
634
635
  end
635
636
 
636
637
  # If STI is used, find the correct subclass for association reflection
@@ -648,12 +649,13 @@ module ActiveRecord
648
649
  fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
649
650
 
650
651
  if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
651
- if association.options[:polymorphic] && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
652
+ if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
652
653
  # support polymorphic belongs_to as "label (Type)"
653
654
  row[association.foreign_type] = $1
654
655
  end
655
656
 
656
- row[fk_name] = ActiveRecord::FixtureSet.identify(value)
657
+ fk_type = association.active_record.columns_hash[association.foreign_key].type
658
+ row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
657
659
  end
658
660
  when :has_many
659
661
  if association.options[:through]
@@ -680,6 +682,10 @@ module ActiveRecord
680
682
  def name
681
683
  @association.name
682
684
  end
685
+
686
+ def primary_key_type
687
+ @association.klass.column_types[@association.klass.primary_key].type
688
+ end
683
689
  end
684
690
 
685
691
  class HasManyThroughProxy < ReflectionProxy # :nodoc:
@@ -690,10 +696,6 @@ module ActiveRecord
690
696
  def lhs_key
691
697
  @association.through_reflection.foreign_key
692
698
  end
693
-
694
- def join_table
695
- @association.through_reflection.table_name
696
- end
697
699
  end
698
700
 
699
701
  private
@@ -701,17 +703,22 @@ module ActiveRecord
701
703
  @primary_key_name ||= model_class && model_class.primary_key
702
704
  end
703
705
 
706
+ def primary_key_type
707
+ @primary_key_type ||= model_class && model_class.column_types[model_class.primary_key].type
708
+ end
709
+
704
710
  def add_join_records(rows, row, association)
705
711
  # This is the case when the join table has no fixtures file
706
712
  if (targets = row.delete(association.name.to_s))
707
- table_name = association.join_table
708
- lhs_key = association.lhs_key
709
- rhs_key = association.rhs_key
713
+ table_name = association.join_table
714
+ column_type = association.primary_key_type
715
+ lhs_key = association.lhs_key
716
+ rhs_key = association.rhs_key
710
717
 
711
718
  targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
712
719
  rows[table_name].concat targets.map { |target|
713
720
  { lhs_key => row[primary_key_name],
714
- rhs_key => ActiveRecord::FixtureSet.identify(target) }
721
+ rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
715
722
  }
716
723
  end
717
724
  end
@@ -792,7 +799,7 @@ module ActiveRecord
792
799
 
793
800
  def find
794
801
  if model_class
795
- model_class.unscoped.find(fixture[model_class.primary_key])
802
+ model_class.find(fixture[model_class.primary_key])
796
803
  else
797
804
  raise FixtureClassNotFound, "No class attached to find."
798
805
  end
@@ -863,11 +870,11 @@ module ActiveRecord
863
870
  def try_to_load_dependency(file_name)
864
871
  require_dependency file_name
865
872
  rescue LoadError => e
866
- unless fixture_class_names.key?(file_name.pluralize)
867
- if ActiveRecord::Base.logger
868
- ActiveRecord::Base.logger.warn("Unable to load #{file_name}, make sure you added it to ActiveSupport::TestCase.set_fixture_class")
869
- ActiveRecord::Base.logger.warn("underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
870
- end
873
+ # Let's hope the developer has included it
874
+ # Let's warn in case this is a subdependency, otherwise
875
+ # subdependency error messages are totally cryptic
876
+ if ActiveRecord::Base.logger
877
+ ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
871
878
  end
872
879
  end
873
880