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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +634 -2185
- data/README.rdoc +15 -10
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations.rb +58 -33
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/association_scope.rb +53 -21
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +32 -44
- data/lib/active_record/associations/collection_proxy.rb +1 -10
- data/lib/active_record/associations/has_many_association.rb +60 -14
- data/lib/active_record/associations/has_many_through_association.rb +34 -23
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/preloader.rb +2 -2
- data/lib/active_record/associations/preloader/association.rb +9 -5
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- data/lib/active_record/attribute.rb +131 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +53 -90
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +85 -42
- data/lib/active_record/attribute_methods/primary_key.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +14 -57
- data/lib/active_record/attribute_methods/serialization.rb +12 -146
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
- data/lib/active_record/attribute_methods/write.rb +8 -23
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attribute_set/builder.rb +32 -0
- data/lib/active_record/attributes.rb +122 -0
- data/lib/active_record/autosave_association.rb +11 -21
- data/lib/active_record/base.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
- data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
- data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
- data/lib/active_record/connection_adapters/column.rb +13 -244
- data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
- data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
- data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +119 -22
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -10
- data/lib/active_record/errors.rb +27 -26
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +52 -45
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +33 -8
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +34 -16
- data/lib/active_record/migration.rb +22 -32
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/model_schema.rb +39 -48
- data/lib/active_record/nested_attributes.rb +8 -18
- data/lib/active_record/persistence.rb +39 -22
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +1 -8
- data/lib/active_record/railtie.rb +17 -10
- data/lib/active_record/railties/databases.rake +47 -42
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +225 -92
- data/lib/active_record/relation.rb +35 -11
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +28 -32
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +42 -20
- data/lib/active_record/relation/merger.rb +0 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -22
- data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
- data/lib/active_record/relation/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- data/lib/active_record/result.rb +16 -9
- data/lib/active_record/sanitization.rb +8 -1
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +51 -9
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +5 -4
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +79 -5
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +37 -5
- data/lib/active_record/tasks/mysql_database_tasks.rb +10 -16
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +35 -21
- data/lib/active_record/type.rb +20 -0
- data/lib/active_record/type/binary.rb +40 -0
- data/lib/active_record/type/boolean.rb +19 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
- data/lib/active_record/type/integer.rb +23 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +51 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +48 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/validations.rb +21 -16
- data/lib/active_record/validations/uniqueness.rb +9 -23
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +71 -14
- 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 |
|
23
|
-
has_many_association = _reflect_on_association(
|
24
|
-
|
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|
|
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(
|
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
|
data/lib/active_record/enum.rb
CHANGED
@@ -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
|
31
|
-
#
|
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
|
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,
|
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
|
-
|
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
|
-
|
152
|
+
set_attribute_was(attr_name, mapping.key(old))
|
154
153
|
end
|
155
154
|
end
|
156
155
|
else
|
data/lib/active_record/errors.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
86
|
-
# when using +find+ method)
|
87
|
-
#
|
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,
|
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 <
|
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
|
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
|
-
#
|
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
|
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
|
-
#
|
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
|
@@ -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
|
18
|
-
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
|
19
|
-
#
|
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
|
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,
|
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
|
-
#
|
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
|
376
|
-
#
|
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
|
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 { |
|
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
|
-
|
537
|
-
|
538
|
-
|
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
|
-
#
|
551
|
-
def self.identify(label)
|
552
|
-
|
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] =
|
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.
|
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
|
-
|
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
|
708
|
-
|
709
|
-
|
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.
|
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
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
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
|
|