activerecord 4.2.0 → 5.2.8.1
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 +5 -5
- data/CHANGELOG.md +640 -928
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -11
- data/examples/performance.rb +32 -31
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +264 -247
- data/lib/active_record/association_relation.rb +24 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +87 -41
- data/lib/active_record/associations/association_scope.rb +106 -132
- data/lib/active_record/associations/belongs_to_association.rb +55 -36
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +29 -38
- data/lib/active_record/associations/builder/belongs_to.rb +77 -30
- data/lib/active_record/associations/builder/collection_association.rb +14 -23
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
- data/lib/active_record/associations/builder/has_many.rb +6 -4
- data/lib/active_record/associations/builder/has_one.rb +13 -6
- data/lib/active_record/associations/builder/singular_association.rb +15 -11
- data/lib/active_record/associations/collection_association.rb +145 -266
- data/lib/active_record/associations/collection_proxy.rb +242 -138
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +35 -75
- data/lib/active_record/associations/has_many_through_association.rb +51 -69
- data/lib/active_record/associations/has_one_association.rb +39 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -154
- data/lib/active_record/associations/preloader/association.rb +85 -116
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +83 -93
- data/lib/active_record/associations/singular_association.rb +27 -40
- data/lib/active_record/associations/through_association.rb +48 -23
- data/lib/active_record/associations.rb +1732 -1596
- data/lib/active_record/attribute_assignment.rb +58 -182
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
- data/lib/active_record/attribute_methods/dirty.rb +94 -125
- data/lib/active_record/attribute_methods/primary_key.rb +86 -71
- data/lib/active_record/attribute_methods/query.rb +4 -2
- data/lib/active_record/attribute_methods/read.rb +45 -63
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
- data/lib/active_record/attribute_methods/write.rb +31 -46
- data/lib/active_record/attribute_methods.rb +170 -117
- data/lib/active_record/attributes.rb +201 -74
- data/lib/active_record/autosave_association.rb +118 -45
- data/lib/active_record/base.rb +60 -48
- data/lib/active_record/callbacks.rb +97 -57
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +37 -13
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
- data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
- data/lib/active_record/connection_adapters/column.rb +50 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +40 -27
- data/lib/active_record/core.rb +205 -202
- data/lib/active_record/counter_cache.rb +80 -37
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +136 -90
- data/lib/active_record/errors.rb +180 -52
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +193 -135
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +148 -112
- data/lib/active_record/integration.rb +70 -28
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +92 -98
- data/lib/active_record/locking/pessimistic.rb +15 -3
- data/lib/active_record/log_subscriber.rb +95 -33
- data/lib/active_record/migration/command_recorder.rb +133 -90
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +594 -267
- data/lib/active_record/model_schema.rb +292 -111
- data/lib/active_record/nested_attributes.rb +266 -214
- data/lib/active_record/no_touching.rb +8 -2
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +350 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +117 -35
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +9 -3
- data/lib/active_record/railties/databases.rake +160 -174
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +447 -288
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +204 -55
- data/lib/active_record/relation/calculations.rb +259 -244
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +290 -253
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +91 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +118 -92
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +446 -389
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -16
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +287 -339
- data/lib/active_record/result.rb +54 -36
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +155 -124
- data/lib/active_record/schema.rb +30 -24
- data/lib/active_record/schema_dumper.rb +91 -87
- data/lib/active_record/schema_migration.rb +19 -19
- data/lib/active_record/scoping/default.rb +102 -84
- data/lib/active_record/scoping/named.rb +81 -32
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +45 -35
- data/lib/active_record/store.rb +42 -36
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +136 -95
- data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +208 -123
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +4 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +30 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type.rb +79 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +41 -32
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -21
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
- data/lib/rails/generators/active_record/migration.rb +18 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +77 -53
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -149
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- 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/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- 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 -30
- data/lib/active_record/type/decimal.rb +0 -40
- 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 -55
- 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 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
# = Active Record Counter Cache
|
3
5
|
module CounterCache
|
@@ -12,13 +14,21 @@ module ActiveRecord
|
|
12
14
|
#
|
13
15
|
# * +id+ - The id of the object you wish to reset a counter on.
|
14
16
|
# * +counters+ - One or more association counters to reset. Association name or counter name can be given.
|
17
|
+
# * <tt>:touch</tt> - Touch timestamp columns when updating.
|
18
|
+
# Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
|
19
|
+
# touch that column or an array of symbols to touch just those ones.
|
15
20
|
#
|
16
21
|
# ==== Examples
|
17
22
|
#
|
18
|
-
# # For Post with id #1
|
23
|
+
# # For the Post with id #1, reset the comments_count
|
19
24
|
# Post.reset_counters(1, :comments)
|
20
|
-
|
25
|
+
#
|
26
|
+
# # Like above, but also touch the +updated_at+ and/or +updated_on+
|
27
|
+
# # attributes.
|
28
|
+
# Post.reset_counters(1, :comments, touch: true)
|
29
|
+
def reset_counters(id, *counters, touch: nil)
|
21
30
|
object = find(id)
|
31
|
+
|
22
32
|
counters.each do |counter_association|
|
23
33
|
has_many_association = _reflect_on_association(counter_association)
|
24
34
|
unless has_many_association
|
@@ -26,7 +36,7 @@ module ActiveRecord
|
|
26
36
|
has_many_association = has_many.find { |association| association.counter_cache_column && association.counter_cache_column.to_sym == counter_association.to_sym }
|
27
37
|
counter_association = has_many_association.plural_name if has_many_association
|
28
38
|
end
|
29
|
-
raise ArgumentError, "'#{
|
39
|
+
raise ArgumentError, "'#{name}' has no association called '#{counter_association}'" unless has_many_association
|
30
40
|
|
31
41
|
if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
|
32
42
|
has_many_association = has_many_association.through_reflection
|
@@ -37,25 +47,33 @@ module ActiveRecord
|
|
37
47
|
reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
38
48
|
counter_name = reflection.counter_cache_column
|
39
49
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
50
|
+
updates = { counter_name => object.send(counter_association).count(:all) }
|
51
|
+
|
52
|
+
if touch
|
53
|
+
names = touch if touch != true
|
54
|
+
updates.merge!(touch_attributes_with_time(*names))
|
55
|
+
end
|
56
|
+
|
57
|
+
unscoped.where(primary_key => object.id).update_all(updates)
|
44
58
|
end
|
45
|
-
|
59
|
+
|
60
|
+
true
|
46
61
|
end
|
47
62
|
|
48
63
|
# A generic "counter updater" implementation, intended primarily to be
|
49
|
-
# used by increment_counter and decrement_counter, but which may also
|
64
|
+
# used by #increment_counter and #decrement_counter, but which may also
|
50
65
|
# be useful on its own. It simply does a direct SQL update for the record
|
51
66
|
# with the given ID, altering the given hash of counters by the amount
|
52
67
|
# given by the corresponding value:
|
53
68
|
#
|
54
69
|
# ==== Parameters
|
55
70
|
#
|
56
|
-
# * +id+ - The id of the object you wish to update a counter on or an
|
71
|
+
# * +id+ - The id of the object you wish to update a counter on or an array of ids.
|
57
72
|
# * +counters+ - A Hash containing the names of the fields
|
58
73
|
# to update as keys and the amount to update the field by as values.
|
74
|
+
# * <tt>:touch</tt> option - Touch timestamp columns when updating.
|
75
|
+
# If attribute names are passed, they are updated along with updated_at/on
|
76
|
+
# attributes.
|
59
77
|
#
|
60
78
|
# ==== Examples
|
61
79
|
#
|
@@ -74,65 +92,92 @@ module ActiveRecord
|
|
74
92
|
# # UPDATE posts
|
75
93
|
# # SET comment_count = COALESCE(comment_count, 0) + 1
|
76
94
|
# # WHERE id IN (10, 15)
|
95
|
+
#
|
96
|
+
# # For the Posts with id of 10 and 15, increment the comment_count by 1
|
97
|
+
# # and update the updated_at value for each counter.
|
98
|
+
# Post.update_counters [10, 15], comment_count: 1, touch: true
|
99
|
+
# # Executes the following SQL:
|
100
|
+
# # UPDATE posts
|
101
|
+
# # SET comment_count = COALESCE(comment_count, 0) + 1,
|
102
|
+
# # `updated_at` = '2016-10-13T09:59:23-05:00'
|
103
|
+
# # WHERE id IN (10, 15)
|
77
104
|
def update_counters(id, counters)
|
105
|
+
touch = counters.delete(:touch)
|
106
|
+
|
78
107
|
updates = counters.map do |counter_name, value|
|
79
|
-
operator = value < 0 ?
|
108
|
+
operator = value < 0 ? "-" : "+"
|
80
109
|
quoted_column = connection.quote_column_name(counter_name)
|
81
110
|
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
|
82
111
|
end
|
83
112
|
|
84
|
-
|
113
|
+
if touch
|
114
|
+
names = touch if touch != true
|
115
|
+
touch_updates = touch_attributes_with_time(*names)
|
116
|
+
updates << sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty?
|
117
|
+
end
|
118
|
+
|
119
|
+
if id.is_a?(Relation) && self == id.klass
|
120
|
+
relation = id
|
121
|
+
else
|
122
|
+
relation = unscoped.where!(primary_key => id)
|
123
|
+
end
|
124
|
+
|
125
|
+
relation.update_all updates.join(", ")
|
85
126
|
end
|
86
127
|
|
87
128
|
# Increment a numeric field by one, via a direct SQL update.
|
88
129
|
#
|
89
130
|
# This method is used primarily for maintaining counter_cache columns that are
|
90
|
-
# used to store aggregate values. For example, a DiscussionBoard may cache
|
131
|
+
# used to store aggregate values. For example, a +DiscussionBoard+ may cache
|
91
132
|
# posts_count and comments_count to avoid running an SQL query to calculate the
|
92
133
|
# number of posts and comments there are, each time it is displayed.
|
93
134
|
#
|
94
135
|
# ==== Parameters
|
95
136
|
#
|
96
137
|
# * +counter_name+ - The name of the field that should be incremented.
|
97
|
-
# * +id+ - The id of the object that should be incremented or an
|
138
|
+
# * +id+ - The id of the object that should be incremented or an array of ids.
|
139
|
+
# * <tt>:touch</tt> - Touch timestamp columns when updating.
|
140
|
+
# Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
|
141
|
+
# touch that column or an array of symbols to touch just those ones.
|
98
142
|
#
|
99
143
|
# ==== Examples
|
100
144
|
#
|
101
|
-
# # Increment the
|
102
|
-
# DiscussionBoard.increment_counter(:
|
103
|
-
|
104
|
-
|
145
|
+
# # Increment the posts_count column for the record with an id of 5
|
146
|
+
# DiscussionBoard.increment_counter(:posts_count, 5)
|
147
|
+
#
|
148
|
+
# # Increment the posts_count column for the record with an id of 5
|
149
|
+
# # and update the updated_at value.
|
150
|
+
# DiscussionBoard.increment_counter(:posts_count, 5, touch: true)
|
151
|
+
def increment_counter(counter_name, id, touch: nil)
|
152
|
+
update_counters(id, counter_name => 1, touch: touch)
|
105
153
|
end
|
106
154
|
|
107
155
|
# Decrement a numeric field by one, via a direct SQL update.
|
108
156
|
#
|
109
|
-
# This works the same as increment_counter but reduces the column value by
|
157
|
+
# This works the same as #increment_counter but reduces the column value by
|
110
158
|
# 1 instead of increasing it.
|
111
159
|
#
|
112
160
|
# ==== Parameters
|
113
161
|
#
|
114
162
|
# * +counter_name+ - The name of the field that should be decremented.
|
115
|
-
# * +id+ - The id of the object that should be decremented or an
|
163
|
+
# * +id+ - The id of the object that should be decremented or an array of ids.
|
164
|
+
# * <tt>:touch</tt> - Touch timestamp columns when updating.
|
165
|
+
# Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
|
166
|
+
# touch that column or an array of symbols to touch just those ones.
|
116
167
|
#
|
117
168
|
# ==== Examples
|
118
169
|
#
|
119
|
-
# # Decrement the
|
120
|
-
# DiscussionBoard.decrement_counter(:
|
121
|
-
|
122
|
-
|
170
|
+
# # Decrement the posts_count column for the record with an id of 5
|
171
|
+
# DiscussionBoard.decrement_counter(:posts_count, 5)
|
172
|
+
#
|
173
|
+
# # Decrement the posts_count column for the record with an id of 5
|
174
|
+
# # and update the updated_at value.
|
175
|
+
# DiscussionBoard.decrement_counter(:posts_count, 5, touch: true)
|
176
|
+
def decrement_counter(counter_name, id, touch: nil)
|
177
|
+
update_counters(id, counter_name => -1, touch: touch)
|
123
178
|
end
|
124
179
|
end
|
125
180
|
|
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
181
|
private
|
137
182
|
|
138
183
|
def _create_record(*)
|
@@ -141,7 +186,6 @@ module ActiveRecord
|
|
141
186
|
each_counter_cached_associations do |association|
|
142
187
|
if send(association.reflection.name)
|
143
188
|
association.increment_counters
|
144
|
-
@_after_create_counter_called = true
|
145
189
|
end
|
146
190
|
end
|
147
191
|
|
@@ -167,9 +211,8 @@ module ActiveRecord
|
|
167
211
|
|
168
212
|
def each_counter_cached_associations
|
169
213
|
_reflections.each do |name, reflection|
|
170
|
-
yield association(name) if reflection.belongs_to? && reflection.counter_cache_column
|
214
|
+
yield association(name.to_sym) if reflection.belongs_to? && reflection.counter_cache_column
|
171
215
|
end
|
172
216
|
end
|
173
|
-
|
174
217
|
end
|
175
218
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# This module exists because ActiveRecord::AttributeMethods::Dirty needs to
|
5
|
+
# define callbacks, but continue to have its version of +save+ be the super
|
6
|
+
# method of ActiveRecord::Callbacks. This will be removed when the removal
|
7
|
+
# of deprecated code removes this need.
|
8
|
+
module DefineCallbacks
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
module ClassMethods # :nodoc:
|
12
|
+
include ActiveModel::Callbacks
|
13
|
+
end
|
14
|
+
|
15
|
+
included do
|
16
|
+
include ActiveModel::Validations::Callbacks
|
17
|
+
|
18
|
+
define_model_callbacks :initialize, :find, :touch, only: :after
|
19
|
+
define_model_callbacks :save, :create, :update, :destroy
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,140 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module DynamicMatchers #:nodoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
private
|
6
|
+
def respond_to_missing?(name, _)
|
7
|
+
if self == Base
|
8
|
+
super
|
9
|
+
else
|
10
|
+
match = Method.match(self, name)
|
11
|
+
match && match.valid? || super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(name, *arguments, &block)
|
12
16
|
match = Method.match(self, name)
|
13
|
-
|
17
|
+
|
18
|
+
if match && match.valid?
|
19
|
+
match.define
|
20
|
+
send(name, *arguments, &block)
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
14
24
|
end
|
15
|
-
end
|
16
25
|
|
17
|
-
|
26
|
+
class Method
|
27
|
+
@matchers = []
|
18
28
|
|
19
|
-
|
20
|
-
|
29
|
+
class << self
|
30
|
+
attr_reader :matchers
|
21
31
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
super
|
27
|
-
end
|
28
|
-
end
|
32
|
+
def match(model, name)
|
33
|
+
klass = matchers.find { |k| k.pattern.match?(name) }
|
34
|
+
klass.new(model, name) if klass
|
35
|
+
end
|
29
36
|
|
30
|
-
|
31
|
-
|
37
|
+
def pattern
|
38
|
+
@pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/
|
39
|
+
end
|
32
40
|
|
33
|
-
|
34
|
-
|
41
|
+
def prefix
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
35
44
|
|
36
|
-
|
37
|
-
|
38
|
-
|
45
|
+
def suffix
|
46
|
+
""
|
47
|
+
end
|
39
48
|
end
|
40
49
|
|
41
|
-
|
42
|
-
@pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/
|
43
|
-
end
|
50
|
+
attr_reader :model, :name, :attribute_names
|
44
51
|
|
45
|
-
def
|
46
|
-
|
52
|
+
def initialize(model, name)
|
53
|
+
@model = model
|
54
|
+
@name = name.to_s
|
55
|
+
@attribute_names = @name.match(self.class.pattern)[1].split("_and_")
|
56
|
+
@attribute_names.map! { |n| @model.attribute_aliases[n] || n }
|
47
57
|
end
|
48
58
|
|
49
|
-
def
|
50
|
-
|
59
|
+
def valid?
|
60
|
+
attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
|
51
61
|
end
|
52
|
-
end
|
53
62
|
|
54
|
-
|
63
|
+
def define
|
64
|
+
model.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
65
|
+
def self.#{name}(#{signature})
|
66
|
+
#{body}
|
67
|
+
end
|
68
|
+
CODE
|
69
|
+
end
|
55
70
|
|
56
|
-
|
57
|
-
@model = model
|
58
|
-
@name = name.to_s
|
59
|
-
@attribute_names = @name.match(self.class.pattern)[1].split('_and_')
|
60
|
-
@attribute_names.map! { |n| @model.attribute_aliases[n] || n }
|
61
|
-
end
|
71
|
+
private
|
62
72
|
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
def define
|
68
|
-
model.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
69
|
-
def self.#{name}(#{signature})
|
70
|
-
#{body}
|
73
|
+
def body
|
74
|
+
"#{finder}(#{attributes_hash})"
|
71
75
|
end
|
72
|
-
CODE
|
73
|
-
end
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
module Finder
|
81
|
-
# Extended in activerecord-deprecated_finders
|
82
|
-
def body
|
83
|
-
result
|
84
|
-
end
|
85
|
-
|
86
|
-
# Extended in activerecord-deprecated_finders
|
87
|
-
def result
|
88
|
-
"#{finder}(#{attributes_hash})"
|
89
|
-
end
|
90
|
-
|
91
|
-
# The parameters in the signature may have reserved Ruby words, in order
|
92
|
-
# to prevent errors, we start each param name with `_`.
|
93
|
-
#
|
94
|
-
# Extended in activerecord-deprecated_finders
|
95
|
-
def signature
|
96
|
-
attribute_names.map { |name| "_#{name}" }.join(', ')
|
97
|
-
end
|
77
|
+
# The parameters in the signature may have reserved Ruby words, in order
|
78
|
+
# to prevent errors, we start each param name with `_`.
|
79
|
+
def signature
|
80
|
+
attribute_names.map { |name| "_#{name}" }.join(", ")
|
81
|
+
end
|
98
82
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
83
|
+
# Given that the parameters starts with `_`, the finder needs to use the
|
84
|
+
# same parameter name.
|
85
|
+
def attributes_hash
|
86
|
+
"{" + attribute_names.map { |name| ":#{name} => _#{name}" }.join(",") + "}"
|
87
|
+
end
|
104
88
|
|
105
|
-
|
106
|
-
|
89
|
+
def finder
|
90
|
+
raise NotImplementedError
|
91
|
+
end
|
107
92
|
end
|
108
|
-
end
|
109
93
|
|
110
|
-
|
111
|
-
|
112
|
-
include Finder
|
94
|
+
class FindBy < Method
|
95
|
+
Method.matchers << self
|
113
96
|
|
114
|
-
|
115
|
-
|
116
|
-
|
97
|
+
def self.prefix
|
98
|
+
"find_by"
|
99
|
+
end
|
117
100
|
|
118
|
-
|
119
|
-
|
101
|
+
def finder
|
102
|
+
"find_by"
|
103
|
+
end
|
120
104
|
end
|
121
|
-
end
|
122
105
|
|
123
|
-
|
124
|
-
|
125
|
-
include Finder
|
106
|
+
class FindByBang < Method
|
107
|
+
Method.matchers << self
|
126
108
|
|
127
|
-
|
128
|
-
|
129
|
-
|
109
|
+
def self.prefix
|
110
|
+
"find_by"
|
111
|
+
end
|
130
112
|
|
131
|
-
|
132
|
-
|
133
|
-
|
113
|
+
def self.suffix
|
114
|
+
"!"
|
115
|
+
end
|
134
116
|
|
135
|
-
|
136
|
-
|
117
|
+
def finder
|
118
|
+
"find_by!"
|
119
|
+
end
|
137
120
|
end
|
138
|
-
end
|
139
121
|
end
|
140
122
|
end
|