activerecord 3.2.6 → 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 +611 -6417
- data/MIT-LICENSE +4 -2
- data/README.rdoc +44 -47
- data/examples/performance.rb +79 -71
- data/examples/simple.rb +6 -5
- data/lib/active_record/aggregations.rb +268 -238
- data/lib/active_record/association_relation.rb +40 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -42
- data/lib/active_record/associations/association.rb +173 -81
- data/lib/active_record/associations/association_scope.rb +124 -92
- data/lib/active_record/associations/belongs_to_association.rb +83 -38
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +11 -9
- data/lib/active_record/associations/builder/association.rb +113 -32
- data/lib/active_record/associations/builder/belongs_to.rb +105 -60
- data/lib/active_record/associations/builder/collection_association.rb +53 -56
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +98 -41
- data/lib/active_record/associations/builder/has_many.rb +11 -63
- data/lib/active_record/associations/builder/has_one.rb +47 -45
- data/lib/active_record/associations/builder/singular_association.rb +30 -18
- data/lib/active_record/associations/collection_association.rb +217 -295
- data/lib/active_record/associations/collection_proxy.rb +1074 -77
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +78 -50
- data/lib/active_record/associations/has_many_through_association.rb +99 -61
- data/lib/active_record/associations/has_one_association.rb +75 -30
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +45 -119
- data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
- data/lib/active_record/associations/join_dependency.rb +208 -164
- data/lib/active_record/associations/preloader/association.rb +93 -87
- data/lib/active_record/associations/preloader/through_association.rb +87 -38
- data/lib/active_record/associations/preloader.rb +134 -110
- data/lib/active_record/associations/singular_association.rb +19 -24
- data/lib/active_record/associations/through_association.rb +61 -27
- data/lib/active_record/associations.rb +1766 -1505
- data/lib/active_record/attribute_assignment.rb +57 -193
- data/lib/active_record/attribute_decorators.rb +90 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +58 -8
- data/lib/active_record/attribute_methods/dirty.rb +187 -67
- data/lib/active_record/attribute_methods/primary_key.rb +100 -78
- data/lib/active_record/attribute_methods/query.rb +10 -8
- data/lib/active_record/attribute_methods/read.rb +29 -118
- data/lib/active_record/attribute_methods/serialization.rb +60 -72
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -42
- data/lib/active_record/attribute_methods/write.rb +36 -44
- data/lib/active_record/attribute_methods.rb +306 -161
- data/lib/active_record/attributes.rb +279 -0
- data/lib/active_record/autosave_association.rb +324 -238
- data/lib/active_record/base.rb +114 -507
- data/lib/active_record/callbacks.rb +147 -83
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +32 -23
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +962 -279
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +32 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +331 -209
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +201 -65
- 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 +510 -289
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1182 -313
- data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +585 -120
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +610 -463
- data/lib/active_record/connection_adapters/column.rb +58 -233
- 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 +75 -207
- 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/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/oid.rb +34 -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 +695 -1052
- data/lib/active_record/connection_adapters/schema_cache.rb +115 -24
- 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 +528 -26
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +267 -0
- data/lib/active_record/core.rb +599 -0
- data/lib/active_record/counter_cache.rb +177 -103
- 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/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +107 -64
- data/lib/active_record/enum.rb +274 -0
- data/lib/active_record/errors.rb +254 -61
- data/lib/active_record/explain.rb +35 -70
- data/lib/active_record/explain_registry.rb +32 -0
- data/lib/active_record/explain_subscriber.rb +18 -8
- 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 +291 -475
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +219 -100
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +175 -17
- 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 +9 -1
- data/lib/active_record/locking/optimistic.rb +106 -92
- data/lib/active_record/locking/pessimistic.rb +23 -11
- data/lib/active_record/log_subscriber.rb +80 -30
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +235 -56
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +17 -0
- data/lib/active_record/migration.rb +917 -301
- data/lib/active_record/model_schema.rb +351 -175
- data/lib/active_record/nested_attributes.rb +366 -235
- data/lib/active_record/no_touching.rb +65 -0
- data/lib/active_record/null_relation.rb +68 -0
- data/lib/active_record/persistence.rb +761 -166
- data/lib/active_record/query_cache.rb +22 -44
- data/lib/active_record/querying.rb +55 -31
- data/lib/active_record/railtie.rb +185 -47
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +5 -4
- data/lib/active_record/railties/controller_runtime.rb +35 -33
- data/lib/active_record/railties/databases.rake +366 -463
- data/lib/active_record/readonly_attributes.rb +4 -6
- data/lib/active_record/reflection.rb +736 -228
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +252 -52
- data/lib/active_record/relation/calculations.rb +340 -270
- data/lib/active_record/relation/delegation.rb +117 -36
- data/lib/active_record/relation/finder_methods.rb +439 -286
- 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/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/predicate_builder.rb +131 -39
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +1163 -221
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +49 -120
- 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/relation.rb +671 -349
- data/lib/active_record/result.rb +149 -15
- data/lib/active_record/runtime_registry.rb +24 -0
- data/lib/active_record/sanitization.rb +153 -133
- data/lib/active_record/schema.rb +22 -19
- data/lib/active_record/schema_dumper.rb +178 -112
- data/lib/active_record/schema_migration.rb +60 -0
- data/lib/active_record/scoping/default.rb +107 -98
- data/lib/active_record/scoping/named.rb +130 -115
- data/lib/active_record/scoping.rb +77 -123
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +10 -6
- data/lib/active_record/statement_cache.rb +148 -0
- data/lib/active_record/store.rb +256 -16
- 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 +93 -39
- data/lib/active_record/touch_later.rb +66 -0
- data/lib/active_record/transactions.rb +260 -129
- data/lib/active_record/translation.rb +3 -1
- 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.rb +78 -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/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +35 -18
- 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 +123 -77
- data/lib/active_record/validations.rb +54 -43
- data/lib/active_record/version.rb +7 -7
- data/lib/active_record.rb +97 -49
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -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/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/nodes.rb +68 -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/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/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +51 -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/migration_generator.rb +59 -9
- 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/migration.rb +41 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +24 -22
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
- data/lib/rails/generators/active_record.rb +10 -16
- metadata +285 -149
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- 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_and_belongs_to_many.rb +0 -60
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
- 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_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -188
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -426
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -579
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -358
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,66 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
class Preloader
|
4
|
-
|
6
|
+
class ThroughAssociation < Association # :nodoc:
|
7
|
+
PRELOADER = ActiveRecord::Associations::Preloader.new
|
5
8
|
|
6
|
-
def
|
7
|
-
|
9
|
+
def initialize(*)
|
10
|
+
super
|
11
|
+
@already_loaded = owners.first.association(through_reflection.name).loaded?
|
8
12
|
end
|
9
13
|
|
10
|
-
def
|
11
|
-
|
14
|
+
def preloaded_records
|
15
|
+
@preloaded_records ||= source_preloaders.flat_map(&:preloaded_records)
|
12
16
|
end
|
13
17
|
|
14
|
-
def
|
15
|
-
|
18
|
+
def records_by_owner
|
19
|
+
return @records_by_owner if defined?(@records_by_owner)
|
20
|
+
source_records_by_owner = source_preloaders.map(&:records_by_owner).reduce(:merge)
|
21
|
+
through_records_by_owner = through_preloaders.map(&:records_by_owner).reduce(:merge)
|
22
|
+
|
23
|
+
@records_by_owner = owners.each_with_object({}) do |owner, result|
|
24
|
+
through_records = through_records_by_owner[owner] || []
|
25
|
+
|
26
|
+
if @already_loaded
|
27
|
+
if source_type = reflection.options[:source_type]
|
28
|
+
through_records = through_records.select do |record|
|
29
|
+
record[reflection.foreign_type] == source_type
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
16
33
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
).run
|
34
|
+
records = through_records.flat_map do |record|
|
35
|
+
source_records_by_owner[record]
|
36
|
+
end
|
21
37
|
|
22
|
-
through_records.each do |owner, records|
|
23
|
-
records.map! { |r| r.send(source_reflection.name) }.flatten!
|
24
38
|
records.compact!
|
39
|
+
records.sort_by! { |rhs| preload_index[rhs] } if scope.order_values.any?
|
40
|
+
records.uniq! if scope.distinct_value
|
41
|
+
result[owner] = records
|
25
42
|
end
|
26
43
|
end
|
27
44
|
|
28
45
|
private
|
46
|
+
def source_preloaders
|
47
|
+
@source_preloaders ||= PRELOADER.preload(middle_records, source_reflection.name, scope)
|
48
|
+
end
|
49
|
+
|
50
|
+
def middle_records
|
51
|
+
through_preloaders.flat_map(&:preloaded_records)
|
52
|
+
end
|
53
|
+
|
54
|
+
def through_preloaders
|
55
|
+
@through_preloaders ||= PRELOADER.preload(owners, through_reflection.name, through_scope)
|
56
|
+
end
|
57
|
+
|
58
|
+
def through_reflection
|
59
|
+
reflection.through_reflection
|
60
|
+
end
|
61
|
+
|
62
|
+
def source_reflection
|
63
|
+
reflection.source_reflection
|
64
|
+
end
|
29
65
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
66
|
+
def preload_index
|
67
|
+
@preload_index ||= preloaded_records.each_with_object({}).with_index do |(record, result), index|
|
68
|
+
result[record] = index
|
69
|
+
end
|
70
|
+
end
|
35
71
|
|
36
|
-
|
37
|
-
|
72
|
+
def through_scope
|
73
|
+
scope = through_reflection.klass.unscoped
|
74
|
+
options = reflection.options
|
38
75
|
|
39
|
-
|
40
|
-
if
|
41
|
-
|
76
|
+
values = reflection_scope.values
|
77
|
+
if annotations = values[:annotate]
|
78
|
+
scope.annotate!(*annotations)
|
42
79
|
end
|
43
80
|
|
44
|
-
[
|
45
|
-
|
46
|
-
|
81
|
+
if options[:source_type]
|
82
|
+
scope.where! reflection.foreign_type => options[:source_type]
|
83
|
+
elsif !reflection_scope.where_clause.empty?
|
84
|
+
scope.where_clause = reflection_scope.where_clause
|
47
85
|
|
48
|
-
|
49
|
-
|
86
|
+
if includes = values[:includes]
|
87
|
+
scope.includes!(source_reflection.name => includes)
|
88
|
+
else
|
89
|
+
scope.includes!(source_reflection.name)
|
90
|
+
end
|
50
91
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
92
|
+
if values[:references] && !values[:references].empty?
|
93
|
+
scope.references!(values[:references])
|
94
|
+
else
|
95
|
+
scope.references!(source_reflection.table_name)
|
96
|
+
end
|
97
|
+
|
98
|
+
if joins = values[:joins]
|
99
|
+
scope.joins!(source_reflection.name => joins)
|
100
|
+
end
|
101
|
+
|
102
|
+
if left_outer_joins = values[:left_outer_joins]
|
103
|
+
scope.left_outer_joins!(source_reflection.name => left_outer_joins)
|
104
|
+
end
|
105
|
+
|
106
|
+
if scope.eager_loading? && order_values = values[:order]
|
107
|
+
scope = scope.order(order_values)
|
108
|
+
end
|
57
109
|
end
|
58
110
|
|
59
|
-
|
111
|
+
scope
|
60
112
|
end
|
61
|
-
|
62
|
-
through_options
|
63
|
-
end
|
64
113
|
end
|
65
114
|
end
|
66
115
|
end
|
@@ -1,48 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
# Implements the details of eager loading of Active Record associations.
|
4
6
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
+
# Suppose that you have the following two Active Record models:
|
8
|
+
#
|
9
|
+
# class Author < ActiveRecord::Base
|
10
|
+
# # columns: name, age
|
11
|
+
# has_many :books
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# class Book < ActiveRecord::Base
|
15
|
+
# # columns: title, sales, author_id
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# When you load an author with all associated books Active Record will make
|
19
|
+
# multiple queries like this:
|
20
|
+
#
|
21
|
+
# Author.includes(:books).where(name: ['bell hooks', 'Homer']).to_a
|
7
22
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# 'name' and 'age', and a Book model with columns 'name' and 'sales'. Using
|
11
|
-
# this strategy, Active Record would try to retrieve all data for an author
|
12
|
-
# and all of its books via a single query:
|
23
|
+
# => SELECT `authors`.* FROM `authors` WHERE `name` IN ('bell hooks', 'Homer')
|
24
|
+
# => SELECT `books`.* FROM `books` WHERE `author_id` IN (2, 5)
|
13
25
|
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
26
|
+
# Active Record saves the ids of the records from the first query to use in
|
27
|
+
# the second. Depending on the number of associations involved there can be
|
28
|
+
# arbitrarily many SQL queries made.
|
17
29
|
#
|
18
|
-
# However,
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
30
|
+
# However, if there is a WHERE clause that spans across tables Active
|
31
|
+
# Record will fall back to a slightly more resource-intensive single query:
|
32
|
+
#
|
33
|
+
# Author.includes(:books).where(books: {title: 'Illiad'}).to_a
|
34
|
+
# => SELECT `authors`.`id` AS t0_r0, `authors`.`name` AS t0_r1, `authors`.`age` AS t0_r2,
|
35
|
+
# `books`.`id` AS t1_r0, `books`.`title` AS t1_r1, `books`.`sales` AS t1_r2
|
36
|
+
# FROM `authors`
|
37
|
+
# LEFT OUTER JOIN `books` ON `authors`.`id` = `books`.`author_id`
|
38
|
+
# WHERE `books`.`title` = 'Illiad'
|
39
|
+
#
|
40
|
+
# This could result in many rows that contain redundant data and it performs poorly at scale
|
41
|
+
# and is therefore only used when necessary.
|
26
42
|
#
|
27
|
-
# The second strategy is to use multiple database queries, one for each
|
28
|
-
# level of association. Since Rails 2.1, this is the default strategy. In
|
29
|
-
# situations where a table join is necessary (e.g. when the +:conditions+
|
30
|
-
# option references an association's column), it will fallback to the table
|
31
|
-
# join strategy.
|
32
43
|
class Preloader #:nodoc:
|
33
|
-
|
34
|
-
autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
|
35
|
-
autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
|
36
|
-
autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
|
44
|
+
extend ActiveSupport::Autoload
|
37
45
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
|
43
|
-
autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
|
44
|
-
|
45
|
-
attr_reader :records, :associations, :options, :model
|
46
|
+
eager_autoload do
|
47
|
+
autoload :Association, "active_record/associations/preloader/association"
|
48
|
+
autoload :ThroughAssociation, "active_record/associations/preloader/through_association"
|
49
|
+
end
|
46
50
|
|
47
51
|
# Eager loads the named associations for the given Active Record record(s).
|
48
52
|
#
|
@@ -68,7 +72,7 @@ module ActiveRecord
|
|
68
72
|
# books.
|
69
73
|
# - a Hash which specifies multiple association names, as well as
|
70
74
|
# association names for the to-be-preloaded association objects. For
|
71
|
-
# example, specifying <tt>{ :
|
75
|
+
# example, specifying <tt>{ author: :avatar }</tt> will preload a
|
72
76
|
# book's author, as well as that author's avatar.
|
73
77
|
#
|
74
78
|
# +:associations+ has the same format as the +:include+ option for
|
@@ -76,102 +80,122 @@ module ActiveRecord
|
|
76
80
|
#
|
77
81
|
# :books
|
78
82
|
# [ :books, :author ]
|
79
|
-
# { :
|
80
|
-
# [ :books, { :
|
81
|
-
|
82
|
-
|
83
|
-
# (which is called under the hood for preloading records). But it is passed
|
84
|
-
# only one level deep in the +associations+ argument, i.e. it's not passed
|
85
|
-
# to the child associations when +associations+ is a Hash.
|
86
|
-
def initialize(records, associations, options = {})
|
87
|
-
@records = Array.wrap(records).compact.uniq
|
88
|
-
@associations = Array.wrap(associations)
|
89
|
-
@options = options
|
90
|
-
end
|
83
|
+
# { author: :avatar }
|
84
|
+
# [ :books, { author: :avatar } ]
|
85
|
+
def preload(records, associations, preload_scope = nil)
|
86
|
+
records = Array.wrap(records).compact
|
91
87
|
|
92
|
-
|
93
|
-
|
94
|
-
|
88
|
+
if records.empty?
|
89
|
+
[]
|
90
|
+
else
|
91
|
+
Array.wrap(associations).flat_map { |association|
|
92
|
+
preloaders_on association, records, preload_scope
|
93
|
+
}
|
95
94
|
end
|
96
95
|
end
|
97
96
|
|
98
97
|
private
|
99
98
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
99
|
+
# Loads all the given data into +records+ for the +association+.
|
100
|
+
def preloaders_on(association, records, scope, polymorphic_parent = false)
|
101
|
+
case association
|
102
|
+
when Hash
|
103
|
+
preloaders_for_hash(association, records, scope, polymorphic_parent)
|
104
|
+
when Symbol, String
|
105
|
+
preloaders_for_one(association, records, scope, polymorphic_parent)
|
106
|
+
else
|
107
|
+
raise ArgumentError, "#{association.inspect} was not recognized for preload"
|
108
|
+
end
|
108
109
|
end
|
109
|
-
end
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
111
|
+
def preloaders_for_hash(association, records, scope, polymorphic_parent)
|
112
|
+
association.flat_map { |parent, child|
|
113
|
+
grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
|
114
|
+
loaders = preloaders_for_reflection(reflection, reflection_records, scope)
|
115
|
+
recs = loaders.flat_map(&:preloaded_records)
|
116
|
+
child_polymorphic_parent = reflection && reflection.options[:polymorphic]
|
117
|
+
loaders.concat Array.wrap(child).flat_map { |assoc|
|
118
|
+
preloaders_on assoc, recs, scope, child_polymorphic_parent
|
119
|
+
}
|
120
|
+
loaders
|
121
|
+
end
|
122
|
+
}
|
115
123
|
end
|
116
|
-
end
|
117
124
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
125
|
+
# Loads all the given data into +records+ for a singular +association+.
|
126
|
+
#
|
127
|
+
# Functions by instantiating a preloader class such as Preloader::Association and
|
128
|
+
# call the +run+ method for each passed in class in the +records+ argument.
|
129
|
+
#
|
130
|
+
# Not all records have the same class, so group then preload group on the reflection
|
131
|
+
# itself so that if various subclass share the same association then we do not split
|
132
|
+
# them unnecessarily
|
133
|
+
#
|
134
|
+
# Additionally, polymorphic belongs_to associations can have multiple associated
|
135
|
+
# classes, depending on the polymorphic_type field. So we group by the classes as
|
136
|
+
# well.
|
137
|
+
def preloaders_for_one(association, records, scope, polymorphic_parent)
|
138
|
+
grouped_records(association, records, polymorphic_parent)
|
139
|
+
.flat_map do |reflection, reflection_records|
|
140
|
+
preloaders_for_reflection reflection, reflection_records, scope
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def preloaders_for_reflection(reflection, records, scope)
|
145
|
+
records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
|
146
|
+
preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope).run
|
129
147
|
end
|
130
148
|
end
|
131
|
-
end
|
132
149
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
150
|
+
def grouped_records(association, records, polymorphic_parent)
|
151
|
+
h = {}
|
152
|
+
records.each do |record|
|
153
|
+
reflection = record.class._reflect_on_association(association)
|
154
|
+
next if polymorphic_parent && !reflection || !record.association(association).klass
|
155
|
+
(h[reflection] ||= []) << record
|
137
156
|
end
|
138
|
-
|
139
|
-
|
157
|
+
h
|
158
|
+
end
|
140
159
|
|
141
|
-
|
142
|
-
|
143
|
-
|
160
|
+
class AlreadyLoaded # :nodoc:
|
161
|
+
def initialize(klass, owners, reflection, preload_scope)
|
162
|
+
@owners = owners
|
163
|
+
@reflection = reflection
|
164
|
+
end
|
144
165
|
|
145
|
-
|
146
|
-
|
147
|
-
"perhaps you misspelled it?"
|
166
|
+
def run
|
167
|
+
self
|
148
168
|
end
|
149
169
|
|
150
|
-
|
151
|
-
|
152
|
-
|
170
|
+
def preloaded_records
|
171
|
+
@preloaded_records ||= records_by_owner.flat_map(&:last)
|
172
|
+
end
|
153
173
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
174
|
+
def records_by_owner
|
175
|
+
@records_by_owner ||= owners.each_with_object({}) do |owner, result|
|
176
|
+
result[owner] = Array(owner.association(reflection.name).target)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
attr_reader :owners, :reflection
|
160
182
|
end
|
161
|
-
end
|
162
183
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
184
|
+
# Returns a class containing the logic needed to load preload the data
|
185
|
+
# and attach it to a relation. The class returned implements a `run` method
|
186
|
+
# that accepts a preloader.
|
187
|
+
def preloader_for(reflection, owners)
|
188
|
+
if owners.first.association(reflection.name).loaded?
|
189
|
+
return AlreadyLoaded
|
190
|
+
end
|
191
|
+
reflection.check_preloadable!
|
192
|
+
|
193
|
+
if reflection.options[:through]
|
194
|
+
ThroughAssociation
|
195
|
+
else
|
196
|
+
Association
|
197
|
+
end
|
173
198
|
end
|
174
|
-
end
|
175
199
|
end
|
176
200
|
end
|
177
201
|
end
|
@@ -1,48 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
class SingularAssociation < Association #:nodoc:
|
4
6
|
# Implements the reader method, e.g. foo.bar for Foo.has_one :bar
|
5
|
-
def reader
|
6
|
-
if
|
7
|
-
klass.uncached { reload }
|
8
|
-
elsif !loaded? || stale_target?
|
7
|
+
def reader
|
8
|
+
if !loaded? || stale_target?
|
9
9
|
reload
|
10
10
|
end
|
11
11
|
|
12
12
|
target
|
13
13
|
end
|
14
14
|
|
15
|
-
# Implements the writer method, e.g. foo.
|
15
|
+
# Implements the writer method, e.g. foo.bar= for Foo.belongs_to :bar
|
16
16
|
def writer(record)
|
17
17
|
replace(record)
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
def create!(attributes = {}, options = {}, &block)
|
25
|
-
create_record(attributes, options, true, &block)
|
26
|
-
end
|
27
|
-
|
28
|
-
def build(attributes = {}, options = {})
|
29
|
-
record = build_record(attributes, options)
|
30
|
-
yield(record) if block_given?
|
20
|
+
def build(attributes = {}, &block)
|
21
|
+
record = build_record(attributes, &block)
|
31
22
|
set_new_record(record)
|
32
23
|
record
|
33
24
|
end
|
34
25
|
|
35
|
-
|
26
|
+
# Implements the reload reader method, e.g. foo.reload_bar for
|
27
|
+
# Foo.has_one :bar
|
28
|
+
def force_reload_reader
|
29
|
+
reload(true)
|
30
|
+
target
|
31
|
+
end
|
36
32
|
|
37
|
-
|
38
|
-
|
33
|
+
private
|
34
|
+
def scope_for_create
|
35
|
+
super.except!(klass.primary_key)
|
39
36
|
end
|
40
37
|
|
41
38
|
def find_target
|
42
|
-
|
39
|
+
super.first
|
43
40
|
end
|
44
41
|
|
45
|
-
# Implemented by subclasses
|
46
42
|
def replace(record)
|
47
43
|
raise NotImplementedError, "Subclasses must implement a replace(record) method"
|
48
44
|
end
|
@@ -51,9 +47,8 @@ module ActiveRecord
|
|
51
47
|
replace(record)
|
52
48
|
end
|
53
49
|
|
54
|
-
def
|
55
|
-
record = build_record(attributes,
|
56
|
-
yield(record) if block_given?
|
50
|
+
def _create_record(attributes, raise_error = false, &block)
|
51
|
+
record = build_record(attributes, &block)
|
57
52
|
saved = record.save
|
58
53
|
set_new_record(record)
|
59
54
|
raise RecordInvalid.new(record) if !saved && raise_error
|