activerecord 4.2.11.3 → 5.0.7.2
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 +1638 -1132
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +7 -2
- data/lib/active_record/aggregations.rb +34 -21
- data/lib/active_record/association_relation.rb +7 -4
- data/lib/active_record/associations.rb +347 -218
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +22 -10
- data/lib/active_record/associations/association_scope.rb +75 -104
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +13 -11
- data/lib/active_record/associations/collection_association.rb +85 -69
- data/lib/active_record/associations/collection_proxy.rb +104 -46
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +21 -78
- data/lib/active_record/associations/has_many_through_association.rb +6 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +38 -22
- data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +52 -71
- data/lib/active_record/associations/preloader/collection_association.rb +0 -7
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +36 -17
- data/lib/active_record/associations/singular_association.rb +13 -1
- data/lib/active_record/associations/through_association.rb +12 -4
- data/lib/active_record/attribute.rb +69 -19
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +69 -44
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +16 -3
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +32 -3
- data/lib/active_record/attribute_set/builder.rb +42 -16
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +54 -17
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +92 -108
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +116 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +77 -41
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +17 -14
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +48 -24
- data/lib/active_record/migration.rb +362 -111
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +270 -73
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +152 -90
- data/lib/active_record/query_cache.rb +18 -23
- data/lib/active_record/querying.rb +12 -11
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +52 -41
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +302 -115
- data/lib/active_record/relation.rb +187 -120
- data/lib/active_record/relation/batches.rb +141 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +92 -117
- data/lib/active_record/relation/delegation.rb +8 -20
- data/lib/active_record/relation/finder_methods.rb +173 -89
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +11 -4
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +105 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +54 -37
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +34 -16
- data/lib/active_record/scoping/default.rb +28 -10
- data/lib/active_record/scoping/named.rb +59 -26
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +3 -5
- data/lib/active_record/statement_cache.rb +17 -15
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +69 -0
- data/lib/active_record/tasks/database_tasks.rb +66 -49
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +63 -0
- data/lib/active_record/transactions.rb +139 -57
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +33 -33
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +58 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -51,11 +51,15 @@ module ActiveRecord
|
|
51
51
|
end
|
52
52
|
|
53
53
|
attrs = args.first
|
54
|
-
if
|
54
|
+
if has_attribute?(inheritance_column)
|
55
55
|
subclass = subclass_from_attributes(attrs)
|
56
|
+
|
57
|
+
if subclass.nil? && base_class == self
|
58
|
+
subclass = subclass_from_attributes(column_defaults)
|
59
|
+
end
|
56
60
|
end
|
57
61
|
|
58
|
-
if subclass
|
62
|
+
if subclass && subclass != self
|
59
63
|
subclass.new(*args, &block)
|
60
64
|
else
|
61
65
|
super
|
@@ -79,20 +83,10 @@ module ActiveRecord
|
|
79
83
|
:true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
|
80
84
|
end
|
81
85
|
|
82
|
-
def symbolized_base_class
|
83
|
-
ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement.')
|
84
|
-
@symbolized_base_class ||= base_class.to_s.to_sym
|
85
|
-
end
|
86
|
-
|
87
|
-
def symbolized_sti_name
|
88
|
-
ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_sti_name` is deprecated and will be removed without replacement.')
|
89
|
-
@symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
|
90
|
-
end
|
91
|
-
|
92
86
|
# Returns the class descending directly from ActiveRecord::Base, or
|
93
87
|
# an abstract class, if any, in the inheritance hierarchy.
|
94
88
|
#
|
95
|
-
# If A extends
|
89
|
+
# If A extends ActiveRecord::Base, A.base_class will return A. If B descends from A
|
96
90
|
# through some arbitrarily deep hierarchy, B.base_class will return A.
|
97
91
|
#
|
98
92
|
# If B < A and C < B and if A is an abstract_class then both B.base_class
|
@@ -173,49 +167,47 @@ module ActiveRecord
|
|
173
167
|
end
|
174
168
|
|
175
169
|
def using_single_table_inheritance?(record)
|
176
|
-
record[inheritance_column].present? &&
|
170
|
+
record[inheritance_column].present? && has_attribute?(inheritance_column)
|
177
171
|
end
|
178
172
|
|
179
173
|
def find_sti_class(type_name)
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
174
|
+
type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
|
175
|
+
subclass = begin
|
176
|
+
if store_full_sti_class
|
177
|
+
ActiveSupport::Dependencies.constantize(type_name)
|
178
|
+
else
|
179
|
+
compute_type(type_name)
|
180
|
+
end
|
181
|
+
rescue NameError
|
182
|
+
raise SubclassNotFound,
|
183
|
+
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
|
184
|
+
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
|
185
|
+
"Please rename this column if you didn't intend it to be used for storing the inheritance class " \
|
186
|
+
"or overwrite #{name}.inheritance_column to use another column for that information."
|
184
187
|
end
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
"Please rename this column if you didn't intend it to be used for storing the inheritance class " +
|
190
|
-
"or overwrite #{name}.inheritance_column to use another column for that information."
|
188
|
+
unless subclass == self || descendants.include?(subclass)
|
189
|
+
raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
|
190
|
+
end
|
191
|
+
subclass
|
191
192
|
end
|
192
193
|
|
193
194
|
def type_condition(table = arel_table)
|
194
|
-
sti_column = table
|
195
|
-
sti_names = ([self] + descendants).map
|
195
|
+
sti_column = arel_attribute(inheritance_column, table)
|
196
|
+
sti_names = ([self] + descendants).map(&:sti_name)
|
196
197
|
|
197
198
|
sti_column.in(sti_names)
|
198
199
|
end
|
199
200
|
|
200
201
|
# Detect the subclass from the inheritance column of attrs. If the inheritance column value
|
201
202
|
# is not self or a valid subclass, raises ActiveRecord::SubclassNotFound
|
202
|
-
# If this is a StrongParameters hash, and access to inheritance_column is not permitted,
|
203
|
-
# this will ignore the inheritance column and return nil
|
204
|
-
def subclass_from_attributes?(attrs)
|
205
|
-
columns_hash.include?(inheritance_column) && attrs.is_a?(Hash)
|
206
|
-
end
|
207
|
-
|
208
203
|
def subclass_from_attributes(attrs)
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
subclass = subclass_name.safe_constantize
|
204
|
+
attrs = attrs.to_h if attrs.respond_to?(:permitted?)
|
205
|
+
if attrs.is_a?(Hash)
|
206
|
+
subclass_name = attrs.with_indifferent_access[inheritance_column]
|
213
207
|
|
214
|
-
|
215
|
-
|
208
|
+
if subclass_name.present?
|
209
|
+
find_sti_class(subclass_name)
|
216
210
|
end
|
217
|
-
|
218
|
-
subclass
|
219
211
|
end
|
220
212
|
end
|
221
213
|
end
|
@@ -10,12 +10,12 @@ module ActiveRecord
|
|
10
10
|
# Indicates the format used to generate the timestamp in the cache key.
|
11
11
|
# Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
|
12
12
|
#
|
13
|
-
# This is +:
|
13
|
+
# This is +:usec+, by default.
|
14
14
|
class_attribute :cache_timestamp_format, :instance_writer => false
|
15
|
-
self.cache_timestamp_format = :
|
15
|
+
self.cache_timestamp_format = :usec
|
16
16
|
end
|
17
17
|
|
18
|
-
# Returns a String, which Action Pack uses for constructing
|
18
|
+
# Returns a String, which Action Pack uses for constructing a URL to this
|
19
19
|
# object. The default implementation returns this record's id as a String,
|
20
20
|
# or nil if this record's unsaved.
|
21
21
|
#
|
@@ -53,18 +53,21 @@ module ActiveRecord
|
|
53
53
|
#
|
54
54
|
# Person.find(5).cache_key(:updated_at, :last_reviewed_at)
|
55
55
|
def cache_key(*timestamp_names)
|
56
|
-
|
57
|
-
when new_record?
|
56
|
+
if new_record?
|
58
57
|
"#{model_name.cache_key}/new"
|
59
|
-
when timestamp_names.any?
|
60
|
-
timestamp = max_updated_column_timestamp(timestamp_names)
|
61
|
-
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
62
|
-
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
63
|
-
when timestamp = max_updated_column_timestamp
|
64
|
-
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
65
|
-
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
66
58
|
else
|
67
|
-
|
59
|
+
timestamp = if timestamp_names.any?
|
60
|
+
max_updated_column_timestamp(timestamp_names)
|
61
|
+
else
|
62
|
+
max_updated_column_timestamp
|
63
|
+
end
|
64
|
+
|
65
|
+
if timestamp
|
66
|
+
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
67
|
+
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
68
|
+
else
|
69
|
+
"#{model_name.cache_key}/#{id}"
|
70
|
+
end
|
68
71
|
end
|
69
72
|
end
|
70
73
|
|
@@ -84,7 +87,7 @@ module ActiveRecord
|
|
84
87
|
# Values longer than 20 characters will be truncated. The value
|
85
88
|
# is truncated word by word.
|
86
89
|
#
|
87
|
-
# user = User.find_by(name: 'David
|
90
|
+
# user = User.find_by(name: 'David Heinemeier Hansson')
|
88
91
|
# user.id # => 125
|
89
92
|
# user_path(user) # => "/users/125-david"
|
90
93
|
#
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'active_record/scoping/default'
|
2
|
+
require 'active_record/scoping/named'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
# This class is used to create a table that keeps track of values and keys such
|
6
|
+
# as which environment migrations were run in.
|
7
|
+
class InternalMetadata < ActiveRecord::Base # :nodoc:
|
8
|
+
class << self
|
9
|
+
def primary_key
|
10
|
+
"key"
|
11
|
+
end
|
12
|
+
|
13
|
+
def table_name
|
14
|
+
"#{table_name_prefix}#{ActiveRecord::Base.internal_metadata_table_name}#{table_name_suffix}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def original_table_name
|
18
|
+
"#{table_name_prefix}active_record_internal_metadatas#{table_name_suffix}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(key, value)
|
22
|
+
find_or_initialize_by(key: key).update_attributes!(value: value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](key)
|
26
|
+
where(key: key).pluck(:value).first
|
27
|
+
end
|
28
|
+
|
29
|
+
def table_exists?
|
30
|
+
ActiveSupport::Deprecation.silence { connection.table_exists?(table_name) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def original_table_exists?
|
34
|
+
# This method will be removed in Rails 5.1
|
35
|
+
# Since it is only necessary when `active_record_internal_metadatas` could exist
|
36
|
+
ActiveSupport::Deprecation.silence { connection.table_exists?(original_table_name) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Creates an internal metadata table with columns +key+ and +value+
|
40
|
+
def create_table
|
41
|
+
if original_table_exists?
|
42
|
+
connection.rename_table(original_table_name, table_name)
|
43
|
+
end
|
44
|
+
unless table_exists?
|
45
|
+
key_options = connection.internal_string_options_for_primary_key
|
46
|
+
|
47
|
+
connection.create_table(table_name, id: false) do |t|
|
48
|
+
t.string :key, key_options
|
49
|
+
t.string :value
|
50
|
+
t.timestamps
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -4,16 +4,32 @@ module ActiveRecord
|
|
4
4
|
return coder unless coder.is_a?(Psych::Coder)
|
5
5
|
|
6
6
|
case coder["active_record_yaml_version"]
|
7
|
-
when
|
7
|
+
when 1 then coder
|
8
8
|
else
|
9
9
|
if coder["attributes"].is_a?(AttributeSet)
|
10
|
-
coder
|
10
|
+
Rails420.convert(klass, coder)
|
11
11
|
else
|
12
12
|
Rails41.convert(klass, coder)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
module Rails420
|
18
|
+
def self.convert(klass, coder)
|
19
|
+
attribute_set = coder["attributes"]
|
20
|
+
|
21
|
+
klass.attribute_names.each do |attr_name|
|
22
|
+
attribute = attribute_set[attr_name]
|
23
|
+
if attribute.type.is_a?(Delegator)
|
24
|
+
type_from_klass = klass.type_for_attribute(attr_name)
|
25
|
+
attribute_set[attr_name] = attribute.with_type(type_from_klass)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
coder
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
17
33
|
module Rails41
|
18
34
|
def self.convert(klass, coder)
|
19
35
|
attributes = klass.attributes_builder
|
@@ -7,6 +7,7 @@ en:
|
|
7
7
|
# Default error messages
|
8
8
|
errors:
|
9
9
|
messages:
|
10
|
+
required: "must exist"
|
10
11
|
taken: "has already been taken"
|
11
12
|
|
12
13
|
# Active Record models configuration
|
@@ -15,8 +16,8 @@ en:
|
|
15
16
|
messages:
|
16
17
|
record_invalid: "Validation failed: %{errors}"
|
17
18
|
restrict_dependent_destroy:
|
18
|
-
|
19
|
-
|
19
|
+
has_one: "Cannot delete record because a dependent %{record} exists"
|
20
|
+
has_many: "Cannot delete record because dependent %{record} exist"
|
20
21
|
# Append your own errors here or at the model/attributes scope.
|
21
22
|
|
22
23
|
# You can define own errors for models or model attributes.
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
11
11
|
#
|
12
12
|
# == Usage
|
13
13
|
#
|
14
|
-
# Active
|
14
|
+
# Active Record supports optimistic locking if the +lock_version+ field is present. Each update to the
|
15
15
|
# record increments the +lock_version+ column and the locking facilities ensure that records instantiated twice
|
16
16
|
# will let the last one saved raise a +StaleObjectError+ if the first was also updated. Example:
|
17
17
|
#
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
# p1.save
|
23
23
|
#
|
24
24
|
# p2.first_name = "should fail"
|
25
|
-
# p2.save # Raises
|
25
|
+
# p2.save # Raises an ActiveRecord::StaleObjectError
|
26
26
|
#
|
27
27
|
# Optimistic locking will also check for stale data when objects are destroyed. Example:
|
28
28
|
#
|
@@ -32,7 +32,7 @@ module ActiveRecord
|
|
32
32
|
# p1.first_name = "Michael"
|
33
33
|
# p1.save
|
34
34
|
#
|
35
|
-
# p2.destroy # Raises
|
35
|
+
# p2.destroy # Raises an ActiveRecord::StaleObjectError
|
36
36
|
#
|
37
37
|
# You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging,
|
38
38
|
# or otherwise apply the business logic needed to resolve the conflict.
|
@@ -93,9 +93,9 @@ module ActiveRecord
|
|
93
93
|
self.class.primary_key => id,
|
94
94
|
lock_col => previous_lock_value,
|
95
95
|
).update_all(
|
96
|
-
|
96
|
+
attributes_for_update(attribute_names).map do |name|
|
97
97
|
[name, _read_attribute(name)]
|
98
|
-
end
|
98
|
+
end.to_h
|
99
99
|
)
|
100
100
|
|
101
101
|
unless affected_rows == 1
|
@@ -125,12 +125,8 @@ module ActiveRecord
|
|
125
125
|
relation = super
|
126
126
|
|
127
127
|
if locking_enabled?
|
128
|
-
|
129
|
-
|
130
|
-
substitute = self.class.connection.substitute_at(column)
|
131
|
-
|
132
|
-
relation = relation.where(self.class.arel_table[column_name].eq(substitute))
|
133
|
-
relation.bind_values << [column, self[column_name].to_i]
|
128
|
+
locking_column = self.class.locking_column
|
129
|
+
relation = relation.where(locking_column => _read_attribute(locking_column))
|
134
130
|
end
|
135
131
|
|
136
132
|
relation
|
@@ -148,13 +144,13 @@ module ActiveRecord
|
|
148
144
|
|
149
145
|
# Set the column to use for optimistic locking. Defaults to +lock_version+.
|
150
146
|
def locking_column=(value)
|
151
|
-
|
147
|
+
reload_schema_from_cache
|
152
148
|
@locking_column = value.to_s
|
153
149
|
end
|
154
150
|
|
155
151
|
# The version column used for optimistic locking. Defaults to +lock_version+.
|
156
152
|
def locking_column
|
157
|
-
|
153
|
+
@locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column)
|
158
154
|
@locking_column
|
159
155
|
end
|
160
156
|
|
@@ -188,12 +184,16 @@ module ActiveRecord
|
|
188
184
|
end
|
189
185
|
end
|
190
186
|
|
191
|
-
class LockingType <
|
192
|
-
def
|
187
|
+
class LockingType < DelegateClass(Type::Value) # :nodoc:
|
188
|
+
def deserialize(value)
|
193
189
|
# `nil` *should* be changed to 0
|
194
190
|
super.to_i
|
195
191
|
end
|
196
192
|
|
193
|
+
def serialize(value)
|
194
|
+
super.to_i
|
195
|
+
end
|
196
|
+
|
197
197
|
def init_with(coder)
|
198
198
|
__setobj__(coder['subtype'])
|
199
199
|
end
|
@@ -51,7 +51,7 @@ module ActiveRecord
|
|
51
51
|
# end
|
52
52
|
#
|
53
53
|
# Database-specific information on row locking:
|
54
|
-
# MySQL: http://dev.mysql.com/doc/refman/5.
|
54
|
+
# MySQL: http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
|
55
55
|
# PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
|
56
56
|
module Pessimistic
|
57
57
|
# Obtain a row lock on this record. Reloads the record to obtain the requested
|
@@ -20,20 +20,6 @@ module ActiveRecord
|
|
20
20
|
@odd = false
|
21
21
|
end
|
22
22
|
|
23
|
-
def render_bind(column, value)
|
24
|
-
if column
|
25
|
-
if column.binary?
|
26
|
-
# This specifically deals with the PG adapter that casts bytea columns into a Hash.
|
27
|
-
value = value[:value] if value.is_a?(Hash)
|
28
|
-
value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
|
29
|
-
end
|
30
|
-
|
31
|
-
[column.name, value]
|
32
|
-
else
|
33
|
-
[nil, value]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
23
|
def sql(event)
|
38
24
|
self.class.runtime += event.duration
|
39
25
|
return unless logger.debug?
|
@@ -47,23 +33,61 @@ module ActiveRecord
|
|
47
33
|
binds = nil
|
48
34
|
|
49
35
|
unless (payload[:binds] || []).empty?
|
50
|
-
|
51
|
-
|
36
|
+
casted_params = type_casted_binds(payload[:type_casted_binds])
|
37
|
+
binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
|
38
|
+
render_bind(attr, value)
|
52
39
|
}.inspect
|
53
40
|
end
|
54
41
|
|
55
|
-
|
56
|
-
|
57
|
-
sql = color(sql, nil, true)
|
58
|
-
else
|
59
|
-
name = color(name, MAGENTA, true)
|
60
|
-
end
|
42
|
+
name = colorize_payload_name(name, payload[:name])
|
43
|
+
sql = color(sql, sql_color(sql), true)
|
61
44
|
|
62
45
|
debug " #{name} #{sql}#{binds}"
|
63
46
|
end
|
64
47
|
|
65
|
-
|
66
|
-
|
48
|
+
private
|
49
|
+
|
50
|
+
def type_casted_binds(casted_binds)
|
51
|
+
casted_binds.respond_to?(:call) ? casted_binds.call : casted_binds
|
52
|
+
end
|
53
|
+
|
54
|
+
def render_bind(attr, value)
|
55
|
+
if attr.is_a?(Array)
|
56
|
+
attr = attr.first
|
57
|
+
elsif attr.type.binary? && attr.value
|
58
|
+
value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
|
59
|
+
end
|
60
|
+
|
61
|
+
[attr && attr.name, value]
|
62
|
+
end
|
63
|
+
|
64
|
+
def colorize_payload_name(name, payload_name)
|
65
|
+
if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
|
66
|
+
color(name, MAGENTA, true)
|
67
|
+
else
|
68
|
+
color(name, CYAN, true)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def sql_color(sql)
|
73
|
+
case sql
|
74
|
+
when /\A\s*rollback/mi
|
75
|
+
RED
|
76
|
+
when /select .*for update/mi, /\A\s*lock/mi
|
77
|
+
WHITE
|
78
|
+
when /\A\s*select/i
|
79
|
+
BLUE
|
80
|
+
when /\A\s*insert/i
|
81
|
+
GREEN
|
82
|
+
when /\A\s*update/i
|
83
|
+
YELLOW
|
84
|
+
when /\A\s*delete/i
|
85
|
+
RED
|
86
|
+
when /transaction\s*\Z/i
|
87
|
+
CYAN
|
88
|
+
else
|
89
|
+
MAGENTA
|
90
|
+
end
|
67
91
|
end
|
68
92
|
|
69
93
|
def logger
|