activerecord 6.0.0
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 +7 -0
- data/CHANGELOG.md +1013 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +219 -0
- data/examples/performance.rb +185 -0
- data/examples/simple.rb +15 -0
- data/lib/active_record.rb +195 -0
- data/lib/active_record/aggregations.rb +285 -0
- data/lib/active_record/association_relation.rb +40 -0
- data/lib/active_record/associations.rb +1865 -0
- data/lib/active_record/associations/alias_tracker.rb +81 -0
- data/lib/active_record/associations/association.rb +332 -0
- data/lib/active_record/associations/association_scope.rb +166 -0
- data/lib/active_record/associations/belongs_to_association.rb +124 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +36 -0
- data/lib/active_record/associations/builder/association.rb +136 -0
- data/lib/active_record/associations/builder/belongs_to.rb +130 -0
- data/lib/active_record/associations/builder/collection_association.rb +72 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +114 -0
- data/lib/active_record/associations/builder/has_many.rb +19 -0
- data/lib/active_record/associations/builder/has_one.rb +64 -0
- data/lib/active_record/associations/builder/singular_association.rb +44 -0
- data/lib/active_record/associations/collection_association.rb +498 -0
- data/lib/active_record/associations/collection_proxy.rb +1128 -0
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +136 -0
- data/lib/active_record/associations/has_many_through_association.rb +220 -0
- data/lib/active_record/associations/has_one_association.rb +118 -0
- data/lib/active_record/associations/has_one_through_association.rb +45 -0
- data/lib/active_record/associations/join_dependency.rb +258 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +80 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
- data/lib/active_record/associations/preloader.rb +201 -0
- data/lib/active_record/associations/preloader/association.rb +133 -0
- data/lib/active_record/associations/preloader/through_association.rb +116 -0
- data/lib/active_record/associations/singular_association.rb +59 -0
- data/lib/active_record/associations/through_association.rb +121 -0
- data/lib/active_record/attribute_assignment.rb +85 -0
- data/lib/active_record/attribute_decorators.rb +90 -0
- data/lib/active_record/attribute_methods.rb +420 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +81 -0
- data/lib/active_record/attribute_methods/dirty.rb +221 -0
- data/lib/active_record/attribute_methods/primary_key.rb +136 -0
- data/lib/active_record/attribute_methods/query.rb +41 -0
- data/lib/active_record/attribute_methods/read.rb +47 -0
- data/lib/active_record/attribute_methods/serialization.rb +90 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
- data/lib/active_record/attribute_methods/write.rb +61 -0
- data/lib/active_record/attributes.rb +279 -0
- data/lib/active_record/autosave_association.rb +508 -0
- data/lib/active_record/base.rb +328 -0
- data/lib/active_record/callbacks.rb +339 -0
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1165 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +85 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +512 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +154 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +251 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +713 -0
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1475 -0
- data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +761 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +821 -0
- data/lib/active_record/connection_adapters/column.rb +95 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +146 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +949 -0
- data/lib/active_record/connection_adapters/schema_cache.rb +141 -0
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -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 +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +557 -0
- data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
- data/lib/active_record/connection_handling.rb +267 -0
- data/lib/active_record/core.rb +599 -0
- data/lib/active_record/counter_cache.rb +193 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +122 -0
- data/lib/active_record/enum.rb +274 -0
- data/lib/active_record/errors.rb +388 -0
- data/lib/active_record/explain.rb +50 -0
- data/lib/active_record/explain_registry.rb +32 -0
- data/lib/active_record/explain_subscriber.rb +34 -0
- data/lib/active_record/fixture_set/file.rb +82 -0
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +738 -0
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +293 -0
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +207 -0
- data/lib/active_record/internal_metadata.rb +53 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +48 -0
- data/lib/active_record/locking/optimistic.rb +197 -0
- data/lib/active_record/locking/pessimistic.rb +89 -0
- data/lib/active_record/log_subscriber.rb +118 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +1397 -0
- data/lib/active_record/migration/command_recorder.rb +284 -0
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +17 -0
- data/lib/active_record/model_schema.rb +542 -0
- data/lib/active_record/nested_attributes.rb +600 -0
- data/lib/active_record/no_touching.rb +65 -0
- data/lib/active_record/null_relation.rb +68 -0
- data/lib/active_record/persistence.rb +967 -0
- data/lib/active_record/query_cache.rb +52 -0
- data/lib/active_record/querying.rb +82 -0
- data/lib/active_record/railtie.rb +263 -0
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +7 -0
- data/lib/active_record/railties/controller_runtime.rb +51 -0
- data/lib/active_record/railties/databases.rake +527 -0
- data/lib/active_record/readonly_attributes.rb +24 -0
- data/lib/active_record/reflection.rb +1042 -0
- data/lib/active_record/relation.rb +859 -0
- data/lib/active_record/relation/batches.rb +290 -0
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/calculations.rb +424 -0
- data/lib/active_record/relation/delegation.rb +130 -0
- data/lib/active_record/relation/finder_methods.rb +552 -0
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +184 -0
- data/lib/active_record/relation/predicate_builder.rb +150 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +1359 -0
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +77 -0
- data/lib/active_record/relation/where_clause.rb +190 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/result.rb +168 -0
- data/lib/active_record/runtime_registry.rb +24 -0
- data/lib/active_record/sanitization.rb +214 -0
- data/lib/active_record/schema.rb +61 -0
- data/lib/active_record/schema_dumper.rb +270 -0
- data/lib/active_record/schema_migration.rb +60 -0
- data/lib/active_record/scoping.rb +106 -0
- data/lib/active_record/scoping/default.rb +151 -0
- data/lib/active_record/scoping/named.rb +217 -0
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +22 -0
- data/lib/active_record/statement_cache.rb +148 -0
- data/lib/active_record/store.rb +290 -0
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +75 -0
- data/lib/active_record/tasks/database_tasks.rb +506 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +167 -0
- data/lib/active_record/touch_later.rb +66 -0
- data/lib/active_record/transactions.rb +493 -0
- data/lib/active_record/translation.rb +24 -0
- data/lib/active_record/type.rb +78 -0
- data/lib/active_record/type/adapter_specific_registry.rb +129 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
- 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 +71 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +21 -0
- data/lib/active_record/type/type_map.rb +62 -0
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/type_caster/connection.rb +34 -0
- data/lib/active_record/type_caster/map.rb +20 -0
- data/lib/active_record/validations.rb +94 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +60 -0
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +68 -0
- data/lib/active_record/validations/uniqueness.rb +226 -0
- data/lib/active_record/version.rb +10 -0
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record.rb +19 -0
- 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.rb +48 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +75 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +49 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
- metadata +415 -0
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# = Active Record Counter Cache
|
5
|
+
module CounterCache
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Resets one or more counter caches to their correct value using an SQL
|
10
|
+
# count query. This is useful when adding new counter caches, or if the
|
11
|
+
# counter has been corrupted or modified directly by SQL.
|
12
|
+
#
|
13
|
+
# ==== Parameters
|
14
|
+
#
|
15
|
+
# * +id+ - The id of the object you wish to reset a counter on.
|
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.
|
20
|
+
#
|
21
|
+
# ==== Examples
|
22
|
+
#
|
23
|
+
# # For the Post with id #1, reset the comments_count
|
24
|
+
# Post.reset_counters(1, :comments)
|
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)
|
30
|
+
object = find(id)
|
31
|
+
|
32
|
+
counters.each do |counter_association|
|
33
|
+
has_many_association = _reflect_on_association(counter_association)
|
34
|
+
unless has_many_association
|
35
|
+
has_many = reflect_on_all_associations(:has_many)
|
36
|
+
has_many_association = has_many.find { |association| association.counter_cache_column && association.counter_cache_column.to_sym == counter_association.to_sym }
|
37
|
+
counter_association = has_many_association.plural_name if has_many_association
|
38
|
+
end
|
39
|
+
raise ArgumentError, "'#{name}' has no association called '#{counter_association}'" unless has_many_association
|
40
|
+
|
41
|
+
if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
|
42
|
+
has_many_association = has_many_association.through_reflection
|
43
|
+
end
|
44
|
+
|
45
|
+
foreign_key = has_many_association.foreign_key.to_s
|
46
|
+
child_class = has_many_association.klass
|
47
|
+
reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
48
|
+
counter_name = reflection.counter_cache_column
|
49
|
+
|
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)
|
58
|
+
end
|
59
|
+
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
# A generic "counter updater" implementation, intended primarily to be
|
64
|
+
# used by #increment_counter and #decrement_counter, but which may also
|
65
|
+
# be useful on its own. It simply does a direct SQL update for the record
|
66
|
+
# with the given ID, altering the given hash of counters by the amount
|
67
|
+
# given by the corresponding value:
|
68
|
+
#
|
69
|
+
# ==== Parameters
|
70
|
+
#
|
71
|
+
# * +id+ - The id of the object you wish to update a counter on or an array of ids.
|
72
|
+
# * +counters+ - A Hash containing the names of the fields
|
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.
|
77
|
+
#
|
78
|
+
# ==== Examples
|
79
|
+
#
|
80
|
+
# # For the Post with id of 5, decrement the comment_count by 1, and
|
81
|
+
# # increment the action_count by 1
|
82
|
+
# Post.update_counters 5, comment_count: -1, action_count: 1
|
83
|
+
# # Executes the following SQL:
|
84
|
+
# # UPDATE posts
|
85
|
+
# # SET comment_count = COALESCE(comment_count, 0) - 1,
|
86
|
+
# # action_count = COALESCE(action_count, 0) + 1
|
87
|
+
# # WHERE id = 5
|
88
|
+
#
|
89
|
+
# # For the Posts with id of 10 and 15, increment the comment_count by 1
|
90
|
+
# Post.update_counters [10, 15], comment_count: 1
|
91
|
+
# # Executes the following SQL:
|
92
|
+
# # UPDATE posts
|
93
|
+
# # SET comment_count = COALESCE(comment_count, 0) + 1
|
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)
|
104
|
+
def update_counters(id, counters)
|
105
|
+
unscoped.where!(primary_key => id).update_counters(counters)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Increment a numeric field by one, via a direct SQL update.
|
109
|
+
#
|
110
|
+
# This method is used primarily for maintaining counter_cache columns that are
|
111
|
+
# used to store aggregate values. For example, a +DiscussionBoard+ may cache
|
112
|
+
# posts_count and comments_count to avoid running an SQL query to calculate the
|
113
|
+
# number of posts and comments there are, each time it is displayed.
|
114
|
+
#
|
115
|
+
# ==== Parameters
|
116
|
+
#
|
117
|
+
# * +counter_name+ - The name of the field that should be incremented.
|
118
|
+
# * +id+ - The id of the object that should be incremented or an array of ids.
|
119
|
+
# * <tt>:touch</tt> - Touch timestamp columns when updating.
|
120
|
+
# Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
|
121
|
+
# touch that column or an array of symbols to touch just those ones.
|
122
|
+
#
|
123
|
+
# ==== Examples
|
124
|
+
#
|
125
|
+
# # Increment the posts_count column for the record with an id of 5
|
126
|
+
# DiscussionBoard.increment_counter(:posts_count, 5)
|
127
|
+
#
|
128
|
+
# # Increment the posts_count column for the record with an id of 5
|
129
|
+
# # and update the updated_at value.
|
130
|
+
# DiscussionBoard.increment_counter(:posts_count, 5, touch: true)
|
131
|
+
def increment_counter(counter_name, id, touch: nil)
|
132
|
+
update_counters(id, counter_name => 1, touch: touch)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Decrement a numeric field by one, via a direct SQL update.
|
136
|
+
#
|
137
|
+
# This works the same as #increment_counter but reduces the column value by
|
138
|
+
# 1 instead of increasing it.
|
139
|
+
#
|
140
|
+
# ==== Parameters
|
141
|
+
#
|
142
|
+
# * +counter_name+ - The name of the field that should be decremented.
|
143
|
+
# * +id+ - The id of the object that should be decremented or an array of ids.
|
144
|
+
# * <tt>:touch</tt> - Touch timestamp columns when updating.
|
145
|
+
# Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
|
146
|
+
# touch that column or an array of symbols to touch just those ones.
|
147
|
+
#
|
148
|
+
# ==== Examples
|
149
|
+
#
|
150
|
+
# # Decrement the posts_count column for the record with an id of 5
|
151
|
+
# DiscussionBoard.decrement_counter(:posts_count, 5)
|
152
|
+
#
|
153
|
+
# # Decrement the posts_count column for the record with an id of 5
|
154
|
+
# # and update the updated_at value.
|
155
|
+
# DiscussionBoard.decrement_counter(:posts_count, 5, touch: true)
|
156
|
+
def decrement_counter(counter_name, id, touch: nil)
|
157
|
+
update_counters(id, counter_name => -1, touch: touch)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
def _create_record(attribute_names = self.attribute_names)
|
163
|
+
id = super
|
164
|
+
|
165
|
+
each_counter_cached_associations do |association|
|
166
|
+
association.increment_counters
|
167
|
+
end
|
168
|
+
|
169
|
+
id
|
170
|
+
end
|
171
|
+
|
172
|
+
def destroy_row
|
173
|
+
affected_rows = super
|
174
|
+
|
175
|
+
if affected_rows > 0
|
176
|
+
each_counter_cached_associations do |association|
|
177
|
+
foreign_key = association.reflection.foreign_key.to_sym
|
178
|
+
unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
|
179
|
+
association.decrement_counters
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
affected_rows
|
185
|
+
end
|
186
|
+
|
187
|
+
def each_counter_cached_associations
|
188
|
+
_reflections.each do |name, reflection|
|
189
|
+
yield association(name.to_sym) if reflection.belongs_to? && reflection.counter_cache_column
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/database_configurations/database_config"
|
4
|
+
require "active_record/database_configurations/hash_config"
|
5
|
+
require "active_record/database_configurations/url_config"
|
6
|
+
|
7
|
+
module ActiveRecord
|
8
|
+
# ActiveRecord::DatabaseConfigurations returns an array of DatabaseConfig
|
9
|
+
# objects (either a HashConfig or UrlConfig) that are constructed from the
|
10
|
+
# application's database configuration hash or URL string.
|
11
|
+
class DatabaseConfigurations
|
12
|
+
class InvalidConfigurationError < StandardError; end
|
13
|
+
|
14
|
+
attr_reader :configurations
|
15
|
+
delegate :any?, to: :configurations
|
16
|
+
|
17
|
+
def initialize(configurations = {})
|
18
|
+
@configurations = build_configs(configurations)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Collects the configs for the environment and optionally the specification
|
22
|
+
# name passed in. To include replica configurations pass <tt>include_replicas: true</tt>.
|
23
|
+
#
|
24
|
+
# If a spec name is provided a single DatabaseConfig object will be
|
25
|
+
# returned, otherwise an array of DatabaseConfig objects will be
|
26
|
+
# returned that corresponds with the environment and type requested.
|
27
|
+
#
|
28
|
+
# ==== Options
|
29
|
+
#
|
30
|
+
# * <tt>env_name:</tt> The environment name. Defaults to +nil+ which will collect
|
31
|
+
# configs for all environments.
|
32
|
+
# * <tt>spec_name:</tt> The specification name (i.e. primary, animals, etc.). Defaults
|
33
|
+
# to +nil+.
|
34
|
+
# * <tt>include_replicas:</tt> Determines whether to include replicas in
|
35
|
+
# the returned list. Most of the time we're only iterating over the write
|
36
|
+
# connection (i.e. migrations don't need to run for the write and read connection).
|
37
|
+
# Defaults to +false+.
|
38
|
+
def configs_for(env_name: nil, spec_name: nil, include_replicas: false)
|
39
|
+
configs = env_with_configs(env_name)
|
40
|
+
|
41
|
+
unless include_replicas
|
42
|
+
configs = configs.select do |db_config|
|
43
|
+
!db_config.replica?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if spec_name
|
48
|
+
configs.find do |db_config|
|
49
|
+
db_config.spec_name == spec_name
|
50
|
+
end
|
51
|
+
else
|
52
|
+
configs
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the config hash that corresponds with the environment
|
57
|
+
#
|
58
|
+
# If the application has multiple databases +default_hash+ will
|
59
|
+
# return the first config hash for the environment.
|
60
|
+
#
|
61
|
+
# { database: "my_db", adapter: "mysql2" }
|
62
|
+
def default_hash(env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s)
|
63
|
+
default = find_db_config(env)
|
64
|
+
default.config if default
|
65
|
+
end
|
66
|
+
alias :[] :default_hash
|
67
|
+
|
68
|
+
# Returns a single DatabaseConfig object based on the requested environment.
|
69
|
+
#
|
70
|
+
# If the application has multiple databases +find_db_config+ will return
|
71
|
+
# the first DatabaseConfig for the environment.
|
72
|
+
def find_db_config(env)
|
73
|
+
configurations.find do |db_config|
|
74
|
+
db_config.env_name == env.to_s ||
|
75
|
+
(db_config.for_current_env? && db_config.spec_name == env.to_s)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the DatabaseConfigurations object as a Hash.
|
80
|
+
def to_h
|
81
|
+
configs = configurations.reverse.inject({}) do |memo, db_config|
|
82
|
+
memo.merge(db_config.to_legacy_hash)
|
83
|
+
end
|
84
|
+
|
85
|
+
Hash[configs.to_a.reverse]
|
86
|
+
end
|
87
|
+
|
88
|
+
# Checks if the application's configurations are empty.
|
89
|
+
#
|
90
|
+
# Aliased to blank?
|
91
|
+
def empty?
|
92
|
+
configurations.empty?
|
93
|
+
end
|
94
|
+
alias :blank? :empty?
|
95
|
+
|
96
|
+
def each
|
97
|
+
throw_getter_deprecation(:each)
|
98
|
+
configurations.each { |config|
|
99
|
+
yield [config.env_name, config.config]
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def first
|
104
|
+
throw_getter_deprecation(:first)
|
105
|
+
config = configurations.first
|
106
|
+
[config.env_name, config.config]
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
def env_with_configs(env = nil)
|
111
|
+
if env
|
112
|
+
configurations.select { |db_config| db_config.env_name == env }
|
113
|
+
else
|
114
|
+
configurations
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def build_configs(configs)
|
119
|
+
return configs.configurations if configs.is_a?(DatabaseConfigurations)
|
120
|
+
return configs if configs.is_a?(Array)
|
121
|
+
|
122
|
+
db_configs = configs.flat_map do |env_name, config|
|
123
|
+
if config.is_a?(Hash) && config.all? { |_, v| v.is_a?(Hash) }
|
124
|
+
walk_configs(env_name.to_s, config)
|
125
|
+
else
|
126
|
+
build_db_config_from_raw_config(env_name.to_s, "primary", config)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
|
131
|
+
|
132
|
+
unless db_configs.find(&:for_current_env?)
|
133
|
+
db_configs << environment_url_config(current_env, "primary", {})
|
134
|
+
end
|
135
|
+
|
136
|
+
merge_db_environment_variables(current_env, db_configs.compact)
|
137
|
+
end
|
138
|
+
|
139
|
+
def walk_configs(env_name, config)
|
140
|
+
config.map do |spec_name, sub_config|
|
141
|
+
build_db_config_from_raw_config(env_name, spec_name.to_s, sub_config)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def build_db_config_from_raw_config(env_name, spec_name, config)
|
146
|
+
case config
|
147
|
+
when String
|
148
|
+
build_db_config_from_string(env_name, spec_name, config)
|
149
|
+
when Hash
|
150
|
+
build_db_config_from_hash(env_name, spec_name, config.stringify_keys)
|
151
|
+
else
|
152
|
+
raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def build_db_config_from_string(env_name, spec_name, config)
|
157
|
+
url = config
|
158
|
+
uri = URI.parse(url)
|
159
|
+
if uri.scheme
|
160
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url)
|
161
|
+
else
|
162
|
+
raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def build_db_config_from_hash(env_name, spec_name, config)
|
167
|
+
if config.has_key?("url")
|
168
|
+
url = config["url"]
|
169
|
+
config_without_url = config.dup
|
170
|
+
config_without_url.delete "url"
|
171
|
+
|
172
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url, config_without_url)
|
173
|
+
else
|
174
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def merge_db_environment_variables(current_env, configs)
|
179
|
+
configs.map do |config|
|
180
|
+
next config if config.url_config? || config.env_name != current_env
|
181
|
+
|
182
|
+
url_config = environment_url_config(current_env, config.spec_name, config.config)
|
183
|
+
url_config || config
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def environment_url_config(env, spec_name, config)
|
188
|
+
url = environment_value_for(spec_name)
|
189
|
+
return unless url
|
190
|
+
|
191
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, spec_name, url, config)
|
192
|
+
end
|
193
|
+
|
194
|
+
def environment_value_for(spec_name)
|
195
|
+
spec_env_key = "#{spec_name.upcase}_DATABASE_URL"
|
196
|
+
url = ENV[spec_env_key]
|
197
|
+
url ||= ENV["DATABASE_URL"] if spec_name == "primary"
|
198
|
+
url
|
199
|
+
end
|
200
|
+
|
201
|
+
def method_missing(method, *args, &blk)
|
202
|
+
case method
|
203
|
+
when :fetch
|
204
|
+
throw_getter_deprecation(method)
|
205
|
+
configs_for(env_name: args.first)
|
206
|
+
when :values
|
207
|
+
throw_getter_deprecation(method)
|
208
|
+
configurations.map(&:config)
|
209
|
+
when :[]=
|
210
|
+
throw_setter_deprecation(method)
|
211
|
+
|
212
|
+
env_name = args[0]
|
213
|
+
config = args[1]
|
214
|
+
|
215
|
+
remaining_configs = configurations.reject { |db_config| db_config.env_name == env_name }
|
216
|
+
new_config = build_configs(env_name => config)
|
217
|
+
new_configs = remaining_configs + new_config
|
218
|
+
|
219
|
+
ActiveRecord::Base.configurations = new_configs
|
220
|
+
else
|
221
|
+
raise NotImplementedError, "`ActiveRecord::Base.configurations` in Rails 6 now returns an object instead of a hash. The `#{method}` method is not supported. Please use `configs_for` or consult the documentation for supported methods."
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def throw_setter_deprecation(method)
|
226
|
+
ActiveSupport::Deprecation.warn("Setting `ActiveRecord::Base.configurations` with `#{method}` is deprecated. Use `ActiveRecord::Base.configurations=` directly to set the configurations instead.")
|
227
|
+
end
|
228
|
+
|
229
|
+
def throw_getter_deprecation(method)
|
230
|
+
ActiveSupport::Deprecation.warn("`ActiveRecord::Base.configurations` no longer returns a hash. Methods that act on the hash like `#{method}` are deprecated and will be removed in Rails 6.1. Use the `configs_for` method to collect and iterate over the database configurations.")
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class DatabaseConfigurations
|
5
|
+
# ActiveRecord::Base.configurations will return either a HashConfig or
|
6
|
+
# UrlConfig respectively. It will never return a DatabaseConfig object,
|
7
|
+
# as this is the parent class for the types of database configuration objects.
|
8
|
+
class DatabaseConfig # :nodoc:
|
9
|
+
attr_reader :env_name, :spec_name
|
10
|
+
|
11
|
+
def initialize(env_name, spec_name)
|
12
|
+
@env_name = env_name
|
13
|
+
@spec_name = spec_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def replica?
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def migrations_paths
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
def url_config?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_legacy_hash
|
29
|
+
{ env_name => config }
|
30
|
+
end
|
31
|
+
|
32
|
+
def for_current_env?
|
33
|
+
env_name == ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|