activerecord 4.2.0 → 6.0.5.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 +852 -801
- data/MIT-LICENSE +4 -2
- data/README.rdoc +14 -13
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +267 -249
- data/lib/active_record/association_relation.rb +26 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -36
- data/lib/active_record/associations/association.rb +137 -55
- data/lib/active_record/associations/association_scope.rb +110 -132
- data/lib/active_record/associations/belongs_to_association.rb +67 -54
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +27 -40
- data/lib/active_record/associations/builder/belongs_to.rb +69 -55
- data/lib/active_record/associations/builder/collection_association.rb +10 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +58 -70
- data/lib/active_record/associations/builder/has_many.rb +8 -4
- data/lib/active_record/associations/builder/has_one.rb +46 -5
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +150 -275
- data/lib/active_record/associations/collection_proxy.rb +253 -152
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +35 -84
- data/lib/active_record/associations/has_many_through_association.rb +62 -80
- data/lib/active_record/associations/has_one_association.rb +62 -49
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +43 -78
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/join_dependency.rb +159 -162
- data/lib/active_record/associations/preloader/association.rb +102 -113
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/preloader.rb +96 -95
- data/lib/active_record/associations/singular_association.rb +18 -45
- data/lib/active_record/associations/through_association.rb +49 -24
- data/lib/active_record/associations.rb +1737 -1596
- data/lib/active_record/attribute_assignment.rb +57 -185
- data/lib/active_record/attribute_decorators.rb +39 -17
- data/lib/active_record/attribute_methods/before_type_cast.rb +14 -5
- data/lib/active_record/attribute_methods/dirty.rb +174 -134
- data/lib/active_record/attribute_methods/primary_key.rb +90 -84
- data/lib/active_record/attribute_methods/query.rb +6 -5
- data/lib/active_record/attribute_methods/read.rb +20 -77
- data/lib/active_record/attribute_methods/serialization.rb +40 -21
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -37
- data/lib/active_record/attribute_methods/write.rb +33 -56
- data/lib/active_record/attribute_methods.rb +124 -143
- data/lib/active_record/attributes.rb +213 -74
- data/lib/active_record/autosave_association.rb +125 -54
- data/lib/active_record/base.rb +60 -49
- data/lib/active_record/callbacks.rb +101 -76
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +36 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +810 -291
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +253 -108
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +83 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +171 -53
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -47
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +383 -239
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +736 -235
- data/lib/active_record/connection_adapters/abstract/transaction.rb +190 -87
- data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -192
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +536 -600
- data/lib/active_record/connection_adapters/column.rb +56 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +174 -153
- 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 +196 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +71 -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 +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -196
- data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +71 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
- 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 +17 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
- 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 +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -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 +67 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -5
- 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 +144 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +465 -291
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +565 -363
- data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -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 +299 -364
- data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
- data/lib/active_record/connection_handling.rb +167 -41
- data/lib/active_record/core.rb +277 -233
- data/lib/active_record/counter_cache.rb +71 -50
- 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 +78 -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 +87 -106
- data/lib/active_record/enum.rb +172 -89
- data/lib/active_record/errors.rb +189 -53
- data/lib/active_record/explain.rb +22 -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/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 +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +225 -497
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +158 -115
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +123 -29
- 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 +3 -2
- data/lib/active_record/locking/optimistic.rb +99 -98
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +76 -33
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +166 -91
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +636 -290
- data/lib/active_record/model_schema.rb +344 -112
- data/lib/active_record/nested_attributes.rb +265 -215
- data/lib/active_record/no_touching.rb +15 -2
- data/lib/active_record/null_relation.rb +24 -38
- data/lib/active_record/persistence.rb +559 -125
- data/lib/active_record/query_cache.rb +19 -23
- data/lib/active_record/querying.rb +44 -30
- data/lib/active_record/railtie.rb +166 -47
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +341 -202
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +461 -302
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +206 -55
- data/lib/active_record/relation/calculations.rb +270 -249
- data/lib/active_record/relation/delegation.rb +76 -84
- data/lib/active_record/relation/finder_methods.rb +287 -255
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +86 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -25
- 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 +7 -1
- data/lib/active_record/relation/predicate_builder.rb +112 -92
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +612 -392
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -17
- data/lib/active_record/relation/where_clause.rb +189 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/relation.rb +533 -340
- data/lib/active_record/result.rb +79 -43
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +144 -121
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +112 -93
- data/lib/active_record/schema_migration.rb +24 -20
- data/lib/active_record/scoping/default.rb +98 -82
- data/lib/active_record/scoping/named.rb +91 -33
- data/lib/active_record/scoping.rb +45 -27
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +73 -36
- data/lib/active_record/store.rb +127 -42
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +90 -0
- data/lib/active_record/tasks/database_tasks.rb +309 -99
- data/lib/active_record/tasks/mysql_database_tasks.rb +58 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -31
- data/lib/active_record/tasks/sqlite_database_tasks.rb +37 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +86 -41
- data/lib/active_record/touch_later.rb +65 -0
- data/lib/active_record/transactions.rb +222 -146
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +126 -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 +12 -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 +29 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +21 -16
- data/lib/active_record/type/type_map.rb +16 -19
- data/lib/active_record/type/unsigned_integer.rb +9 -8
- data/lib/active_record/type.rb +77 -23
- 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 +12 -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 +43 -46
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +44 -21
- 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 +256 -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 +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -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 +42 -37
- 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 → migration.rb.tt} +11 -8
- data/lib/rails/generators/active_record/migration.rb +30 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +174 -63
- 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/integer.rb +0 -11
- 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/migration/templates/create_table_migration.rb +0 -22
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
- /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
|
module Associations
|
3
5
|
# = Active Record Association Collection
|
@@ -10,9 +12,9 @@ module ActiveRecord
|
|
10
12
|
# HasManyAssociation => has_many
|
11
13
|
# HasManyThroughAssociation + ThroughAssociation => has_many :through
|
12
14
|
#
|
13
|
-
# CollectionAssociation class provides common methods to the collections
|
15
|
+
# The CollectionAssociation class provides common methods to the collections
|
14
16
|
# defined by +has_and_belongs_to_many+, +has_many+ or +has_many+ with
|
15
|
-
# +:through association+ option.
|
17
|
+
# the +:through association+ option.
|
16
18
|
#
|
17
19
|
# You need to be careful with assumptions regarding the target: The proxy
|
18
20
|
# does not fetch records from the database until it needs them, but new
|
@@ -24,22 +26,14 @@ module ActiveRecord
|
|
24
26
|
# If you need to work on all current children, new and existing records,
|
25
27
|
# +load_target+ and the +loaded+ flag are your friends.
|
26
28
|
class CollectionAssociation < Association #:nodoc:
|
27
|
-
|
28
29
|
# Implements the reader method, e.g. foo.items for Foo.has_many :items
|
29
|
-
def reader
|
30
|
-
if
|
31
|
-
klass.uncached { reload }
|
32
|
-
elsif stale_target?
|
30
|
+
def reader
|
31
|
+
if stale_target?
|
33
32
|
reload
|
34
33
|
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
# or else a post-save proxy will still lack the id
|
39
|
-
@new_record_proxy ||= CollectionProxy.create(klass, self)
|
40
|
-
else
|
41
|
-
@proxy ||= CollectionProxy.create(klass, self)
|
42
|
-
end
|
35
|
+
@proxy ||= CollectionProxy.create(klass, self)
|
36
|
+
@proxy.reset_scope
|
43
37
|
end
|
44
38
|
|
45
39
|
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
|
@@ -50,107 +44,75 @@ module ActiveRecord
|
|
50
44
|
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
|
51
45
|
def ids_reader
|
52
46
|
if loaded?
|
53
|
-
|
54
|
-
|
55
|
-
|
47
|
+
target.pluck(reflection.association_primary_key)
|
48
|
+
elsif !target.empty?
|
49
|
+
load_target.pluck(reflection.association_primary_key)
|
56
50
|
else
|
57
|
-
|
58
|
-
scope.pluck(column)
|
51
|
+
@association_ids ||= scope.pluck(reflection.association_primary_key)
|
59
52
|
end
|
60
53
|
end
|
61
54
|
|
62
55
|
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
|
63
56
|
def ids_writer(ids)
|
64
|
-
|
65
|
-
|
66
|
-
ids
|
67
|
-
|
57
|
+
primary_key = reflection.association_primary_key
|
58
|
+
pk_type = klass.type_for_attribute(primary_key)
|
59
|
+
ids = Array(ids).reject(&:blank?)
|
60
|
+
ids.map! { |i| pk_type.cast(i) }
|
61
|
+
|
62
|
+
records = klass.where(primary_key => ids).index_by do |r|
|
63
|
+
r.public_send(primary_key)
|
64
|
+
end.values_at(*ids).compact
|
65
|
+
|
66
|
+
if records.size != ids.size
|
67
|
+
found_ids = records.map { |record| record.public_send(primary_key) }
|
68
|
+
not_found_ids = ids - found_ids
|
69
|
+
klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids)
|
70
|
+
else
|
71
|
+
replace(records)
|
72
|
+
end
|
68
73
|
end
|
69
74
|
|
70
75
|
def reset
|
71
76
|
super
|
72
77
|
@target = []
|
73
|
-
|
74
|
-
|
75
|
-
def select(*fields)
|
76
|
-
if block_given?
|
77
|
-
load_target.select.each { |e| yield e }
|
78
|
-
else
|
79
|
-
scope.select(*fields)
|
80
|
-
end
|
78
|
+
@association_ids = nil
|
81
79
|
end
|
82
80
|
|
83
81
|
def find(*args)
|
84
|
-
if
|
85
|
-
|
86
|
-
|
87
|
-
if options[:inverse_of] && loaded?
|
88
|
-
args_flatten = args.flatten
|
89
|
-
raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args_flatten.blank?
|
90
|
-
result = find_by_scan(*args)
|
91
|
-
|
92
|
-
result_size = Array(result).size
|
93
|
-
if !result || result_size != args_flatten.size
|
94
|
-
scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
|
95
|
-
else
|
96
|
-
result
|
97
|
-
end
|
98
|
-
else
|
99
|
-
scope.find(*args)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def first(*args)
|
105
|
-
first_nth_or_last(:first, *args)
|
106
|
-
end
|
107
|
-
|
108
|
-
def second(*args)
|
109
|
-
first_nth_or_last(:second, *args)
|
110
|
-
end
|
111
|
-
|
112
|
-
def third(*args)
|
113
|
-
first_nth_or_last(:third, *args)
|
114
|
-
end
|
82
|
+
if options[:inverse_of] && loaded?
|
83
|
+
args_flatten = args.flatten
|
84
|
+
model = scope.klass
|
115
85
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
def fifth(*args)
|
121
|
-
first_nth_or_last(:fifth, *args)
|
122
|
-
end
|
86
|
+
if args_flatten.blank?
|
87
|
+
error_message = "Couldn't find #{model.name} without an ID"
|
88
|
+
raise RecordNotFound.new(error_message, model.name, model.primary_key, args)
|
89
|
+
end
|
123
90
|
|
124
|
-
|
125
|
-
first_nth_or_last(:forty_two, *args)
|
126
|
-
end
|
91
|
+
result = find_by_scan(*args)
|
127
92
|
|
128
|
-
|
129
|
-
|
93
|
+
result_size = Array(result).size
|
94
|
+
if !result || result_size != args_flatten.size
|
95
|
+
scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
|
96
|
+
else
|
97
|
+
result
|
98
|
+
end
|
99
|
+
else
|
100
|
+
scope.find(*args)
|
101
|
+
end
|
130
102
|
end
|
131
103
|
|
132
104
|
def build(attributes = {}, &block)
|
133
105
|
if attributes.is_a?(Array)
|
134
106
|
attributes.collect { |attr| build(attr, &block) }
|
135
107
|
else
|
136
|
-
add_to_target(build_record(attributes))
|
137
|
-
yield(record) if block_given?
|
138
|
-
end
|
108
|
+
add_to_target(build_record(attributes, &block))
|
139
109
|
end
|
140
110
|
end
|
141
111
|
|
142
|
-
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
def create!(attributes = {}, &block)
|
147
|
-
_create_record(attributes, true, &block)
|
148
|
-
end
|
149
|
-
|
150
|
-
# Add +records+ to this association. Returns +self+ so method calls may
|
151
|
-
# be chained. Since << flattens its argument list and inserts each record,
|
152
|
-
# +push+ and +concat+ behave identically.
|
112
|
+
# Add +records+ to this association. Since +<<+ flattens its argument list
|
113
|
+
# and inserts each record, +push+ and +concat+ behave identically.
|
153
114
|
def concat(*records)
|
115
|
+
records = records.flatten
|
154
116
|
if owner.new_record?
|
155
117
|
load_target
|
156
118
|
concat_records(records)
|
@@ -193,12 +155,12 @@ module ActiveRecord
|
|
193
155
|
end
|
194
156
|
|
195
157
|
dependent = if dependent
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
158
|
+
dependent
|
159
|
+
elsif options[:dependent] == :destroy
|
160
|
+
:delete_all
|
161
|
+
else
|
162
|
+
options[:dependent]
|
163
|
+
end
|
202
164
|
|
203
165
|
delete_or_nullify_all_records(dependent).tap do
|
204
166
|
reset
|
@@ -216,32 +178,6 @@ module ActiveRecord
|
|
216
178
|
end
|
217
179
|
end
|
218
180
|
|
219
|
-
# Count all records using SQL. Construct options and pass them with
|
220
|
-
# scope to the target class's +count+.
|
221
|
-
def count(column_name = nil, count_options = {})
|
222
|
-
# TODO: Remove count_options argument as soon we remove support to
|
223
|
-
# activerecord-deprecated_finders.
|
224
|
-
column_name, count_options = nil, column_name if column_name.is_a?(Hash)
|
225
|
-
|
226
|
-
relation = scope
|
227
|
-
if association_scope.distinct_value
|
228
|
-
# This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
|
229
|
-
column_name ||= reflection.klass.primary_key
|
230
|
-
relation = relation.distinct
|
231
|
-
end
|
232
|
-
|
233
|
-
value = relation.count(column_name)
|
234
|
-
|
235
|
-
limit = options[:limit]
|
236
|
-
offset = options[:offset]
|
237
|
-
|
238
|
-
if limit || offset
|
239
|
-
[ [value - offset.to_i, 0].max, limit.to_i ].min
|
240
|
-
else
|
241
|
-
value
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
181
|
# Removes +records+ from this association calling +before_remove+ and
|
246
182
|
# +after_remove+ callbacks.
|
247
183
|
#
|
@@ -250,12 +186,7 @@ module ActiveRecord
|
|
250
186
|
# are actually removed from the database, that depends precisely on
|
251
187
|
# +delete_records+. They are in any case removed from the collection.
|
252
188
|
def delete(*records)
|
253
|
-
|
254
|
-
_options = records.extract_options!
|
255
|
-
dependent = _options[:dependent] || options[:dependent]
|
256
|
-
|
257
|
-
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
|
258
|
-
delete_or_destroy(records, dependent)
|
189
|
+
delete_or_destroy(records, options[:dependent])
|
259
190
|
end
|
260
191
|
|
261
192
|
# Deletes the +records+ and removes them from this association calling
|
@@ -264,8 +195,6 @@ module ActiveRecord
|
|
264
195
|
# Note that this method removes records from the database ignoring the
|
265
196
|
# +:dependent+ option.
|
266
197
|
def destroy(*records)
|
267
|
-
return if records.empty?
|
268
|
-
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
|
269
198
|
delete_or_destroy(records, :destroy)
|
270
199
|
end
|
271
200
|
|
@@ -281,30 +210,19 @@ module ActiveRecord
|
|
281
210
|
# +count_records+, which is a method descendants have to provide.
|
282
211
|
def size
|
283
212
|
if !find_target? || loaded?
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
end
|
289
|
-
elsif !loaded? && !association_scope.group_values.empty?
|
213
|
+
target.size
|
214
|
+
elsif @association_ids
|
215
|
+
@association_ids.size
|
216
|
+
elsif !association_scope.group_values.empty?
|
290
217
|
load_target.size
|
291
|
-
elsif !
|
292
|
-
unsaved_records = target.select
|
218
|
+
elsif !association_scope.distinct_value && !target.empty?
|
219
|
+
unsaved_records = target.select(&:new_record?)
|
293
220
|
unsaved_records.size + count_records
|
294
221
|
else
|
295
222
|
count_records
|
296
223
|
end
|
297
224
|
end
|
298
225
|
|
299
|
-
# Returns the size of the collection calling +size+ on the target.
|
300
|
-
#
|
301
|
-
# If the collection has been already loaded +length+ and +size+ are
|
302
|
-
# equivalent. If not and you are going to need the records anyway this
|
303
|
-
# method will take one less query. Otherwise +size+ is more efficient.
|
304
|
-
def length
|
305
|
-
load_target.size
|
306
|
-
end
|
307
|
-
|
308
226
|
# Returns true if the collection is empty.
|
309
227
|
#
|
310
228
|
# If the collection has been loaded
|
@@ -314,41 +232,13 @@ module ActiveRecord
|
|
314
232
|
# loaded and you are going to fetch the records anyway it is better to
|
315
233
|
# check <tt>collection.length.zero?</tt>.
|
316
234
|
def empty?
|
317
|
-
if loaded?
|
235
|
+
if loaded? || @association_ids || reflection.has_cached_counter?
|
318
236
|
size.zero?
|
319
237
|
else
|
320
|
-
|
238
|
+
target.empty? && !scope.exists?
|
321
239
|
end
|
322
240
|
end
|
323
241
|
|
324
|
-
# Returns true if the collections is not empty.
|
325
|
-
# Equivalent to +!collection.empty?+.
|
326
|
-
def any?
|
327
|
-
if block_given?
|
328
|
-
load_target.any? { |*block_args| yield(*block_args) }
|
329
|
-
else
|
330
|
-
!empty?
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
# Returns true if the collection has more than 1 record.
|
335
|
-
# Equivalent to +collection.size > 1+.
|
336
|
-
def many?
|
337
|
-
if block_given?
|
338
|
-
load_target.many? { |*block_args| yield(*block_args) }
|
339
|
-
else
|
340
|
-
size > 1
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
def distinct
|
345
|
-
seen = {}
|
346
|
-
load_target.find_all do |record|
|
347
|
-
seen[record.id] = true unless seen.key?(record.id)
|
348
|
-
end
|
349
|
-
end
|
350
|
-
alias uniq distinct
|
351
|
-
|
352
242
|
# Replace this collection with +other_array+. This will perform a diff
|
353
243
|
# and delete/add only records that have changed.
|
354
244
|
def replace(other_array)
|
@@ -361,6 +251,8 @@ module ActiveRecord
|
|
361
251
|
replace_common_records_in_memory(other_array, original_target)
|
362
252
|
if other_array != original_target
|
363
253
|
transaction { replace_records(other_array, original_target) }
|
254
|
+
else
|
255
|
+
other_array
|
364
256
|
end
|
365
257
|
end
|
366
258
|
end
|
@@ -393,25 +285,9 @@ module ActiveRecord
|
|
393
285
|
replace_on_target(record, index, skip_callbacks, &block)
|
394
286
|
end
|
395
287
|
|
396
|
-
def
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
if index
|
401
|
-
@target[index] = record
|
402
|
-
else
|
403
|
-
@target << record
|
404
|
-
end
|
405
|
-
|
406
|
-
callback(:after_add, record) unless skip_callbacks
|
407
|
-
set_inverse_instance(record)
|
408
|
-
|
409
|
-
record
|
410
|
-
end
|
411
|
-
|
412
|
-
def scope(opts = {})
|
413
|
-
scope = super()
|
414
|
-
scope.none! if opts.fetch(:nullify, true) && null_scope?
|
288
|
+
def scope
|
289
|
+
scope = super
|
290
|
+
scope.none! if null_scope?
|
415
291
|
scope
|
416
292
|
end
|
417
293
|
|
@@ -419,34 +295,13 @@ module ActiveRecord
|
|
419
295
|
owner.new_record? && !foreign_key_present?
|
420
296
|
end
|
421
297
|
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
klass.current_scope ||
|
427
|
-
klass.default_scopes.any?
|
428
|
-
|
429
|
-
return scope.to_a
|
430
|
-
end
|
431
|
-
|
432
|
-
conn = klass.connection
|
433
|
-
sc = reflection.association_scope_cache(conn, owner) do
|
434
|
-
StatementCache.create(conn) { |params|
|
435
|
-
as = AssociationScope.create { params.bind }
|
436
|
-
target_scope.merge as.scope(self, conn)
|
437
|
-
}
|
438
|
-
end
|
439
|
-
|
440
|
-
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
441
|
-
sc.execute binds, klass, klass.connection
|
298
|
+
def find_from_target?
|
299
|
+
loaded? ||
|
300
|
+
owner.new_record? ||
|
301
|
+
target.any? { |record| record.new_record? || record.changed? }
|
442
302
|
end
|
443
303
|
|
444
|
-
|
445
|
-
records = get_records
|
446
|
-
records.each { |record| set_inverse_instance(record) }
|
447
|
-
records
|
448
|
-
end
|
449
|
-
|
304
|
+
private
|
450
305
|
# We have some records loaded from the database (persisted) and some that are
|
451
306
|
# in-memory (memory). The same record may be represented in the persisted array
|
452
307
|
# and in the memory array.
|
@@ -464,7 +319,7 @@ module ActiveRecord
|
|
464
319
|
persisted.map! do |record|
|
465
320
|
if mem_record = memory.delete(record)
|
466
321
|
|
467
|
-
((record.attribute_names & mem_record.attribute_names) - mem_record.
|
322
|
+
((record.attribute_names & mem_record.attribute_names) - mem_record.changed_attribute_names_to_save).each do |name|
|
468
323
|
mem_record[name] = record[name]
|
469
324
|
end
|
470
325
|
|
@@ -477,6 +332,13 @@ module ActiveRecord
|
|
477
332
|
persisted + memory
|
478
333
|
end
|
479
334
|
|
335
|
+
def build_record(attributes)
|
336
|
+
previous = klass.current_scope(true) if block_given?
|
337
|
+
super
|
338
|
+
ensure
|
339
|
+
klass.current_scope = previous if previous
|
340
|
+
end
|
341
|
+
|
480
342
|
def _create_record(attributes, raise = false, &block)
|
481
343
|
unless owner.persisted?
|
482
344
|
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
@@ -485,28 +347,35 @@ module ActiveRecord
|
|
485
347
|
if attributes.is_a?(Array)
|
486
348
|
attributes.collect { |attr| _create_record(attr, raise, &block) }
|
487
349
|
else
|
350
|
+
record = build_record(attributes, &block)
|
488
351
|
transaction do
|
489
|
-
|
490
|
-
|
491
|
-
insert_record(record, true, raise)
|
352
|
+
result = nil
|
353
|
+
add_to_target(record) do
|
354
|
+
result = insert_record(record, true, raise) {
|
355
|
+
@_was_loaded = loaded?
|
356
|
+
}
|
492
357
|
end
|
358
|
+
raise ActiveRecord::Rollback unless result
|
493
359
|
end
|
360
|
+
record
|
494
361
|
end
|
495
362
|
end
|
496
363
|
|
497
364
|
# Do the relevant stuff to insert the given record into the association collection.
|
498
|
-
def insert_record(record, validate = true, raise = false)
|
499
|
-
raise
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
365
|
+
def insert_record(record, validate = true, raise = false, &block)
|
366
|
+
if raise
|
367
|
+
record.save!(validate: validate, &block)
|
368
|
+
else
|
369
|
+
record.save(validate: validate, &block)
|
370
|
+
end
|
504
371
|
end
|
505
372
|
|
506
373
|
def delete_or_destroy(records, method)
|
374
|
+
return if records.empty?
|
375
|
+
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
|
507
376
|
records = records.flatten
|
508
377
|
records.each { |record| raise_on_type_mismatch!(record) }
|
509
|
-
existing_records = records.reject
|
378
|
+
existing_records = records.reject(&:new_record?)
|
510
379
|
|
511
380
|
if existing_records.empty?
|
512
381
|
remove_records(existing_records, records, method)
|
@@ -516,24 +385,28 @@ module ActiveRecord
|
|
516
385
|
end
|
517
386
|
|
518
387
|
def remove_records(existing_records, records, method)
|
519
|
-
|
388
|
+
catch(:abort) do
|
389
|
+
records.each { |record| callback(:before_remove, record) }
|
390
|
+
end || return
|
520
391
|
|
521
392
|
delete_records(existing_records, method) if existing_records.any?
|
522
|
-
|
393
|
+
@target -= records
|
394
|
+
@association_ids = nil
|
523
395
|
|
524
396
|
records.each { |record| callback(:after_remove, record) }
|
525
397
|
end
|
526
398
|
|
527
|
-
# Delete the given records from the association,
|
528
|
-
#
|
399
|
+
# Delete the given records from the association,
|
400
|
+
# using one of the methods +:destroy+, +:delete_all+
|
401
|
+
# or +:nullify+ (or +nil+, in which case a default is used).
|
529
402
|
def delete_records(records, method)
|
530
403
|
raise NotImplementedError
|
531
404
|
end
|
532
405
|
|
533
406
|
def replace_records(new_target, original_target)
|
534
|
-
delete(target
|
407
|
+
delete(difference(target, new_target))
|
535
408
|
|
536
|
-
unless concat(new_target
|
409
|
+
unless concat(difference(new_target, target))
|
537
410
|
@target = original_target
|
538
411
|
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
|
539
412
|
"new records could not be saved."
|
@@ -543,24 +416,55 @@ module ActiveRecord
|
|
543
416
|
end
|
544
417
|
|
545
418
|
def replace_common_records_in_memory(new_target, original_target)
|
546
|
-
common_records = new_target
|
419
|
+
common_records = intersection(new_target, original_target)
|
547
420
|
common_records.each do |record|
|
548
421
|
skip_callbacks = true
|
549
422
|
replace_on_target(record, @target.index(record), skip_callbacks)
|
550
423
|
end
|
551
424
|
end
|
552
425
|
|
553
|
-
def concat_records(records,
|
426
|
+
def concat_records(records, raise = false)
|
554
427
|
result = true
|
555
428
|
|
556
|
-
records.
|
429
|
+
records.each do |record|
|
557
430
|
raise_on_type_mismatch!(record)
|
558
|
-
add_to_target(record) do
|
559
|
-
|
431
|
+
add_to_target(record) do
|
432
|
+
unless owner.new_record?
|
433
|
+
result &&= insert_record(record, true, raise) {
|
434
|
+
@_was_loaded = loaded?
|
435
|
+
}
|
436
|
+
end
|
560
437
|
end
|
561
438
|
end
|
562
439
|
|
563
|
-
|
440
|
+
raise ActiveRecord::Rollback unless result
|
441
|
+
|
442
|
+
records
|
443
|
+
end
|
444
|
+
|
445
|
+
def replace_on_target(record, index, skip_callbacks)
|
446
|
+
catch(:abort) do
|
447
|
+
callback(:before_add, record)
|
448
|
+
end || return unless skip_callbacks
|
449
|
+
|
450
|
+
set_inverse_instance(record)
|
451
|
+
|
452
|
+
@_was_loaded = true
|
453
|
+
|
454
|
+
yield(record) if block_given?
|
455
|
+
|
456
|
+
if index
|
457
|
+
target[index] = record
|
458
|
+
elsif @_was_loaded || !loaded?
|
459
|
+
@association_ids = nil
|
460
|
+
target << record
|
461
|
+
end
|
462
|
+
|
463
|
+
callback(:after_add, record) unless skip_callbacks
|
464
|
+
|
465
|
+
record
|
466
|
+
ensure
|
467
|
+
@_was_loaded = nil
|
564
468
|
end
|
565
469
|
|
566
470
|
def callback(method, record)
|
@@ -574,31 +478,12 @@ module ActiveRecord
|
|
574
478
|
owner.class.send(full_callback_name)
|
575
479
|
end
|
576
480
|
|
577
|
-
# Should we deal with assoc.first or assoc.last by issuing an independent query to
|
578
|
-
# the database, or by getting the target, and then taking the first/last item from that?
|
579
|
-
#
|
580
|
-
# If the args is just a non-empty options hash, go to the database.
|
581
|
-
#
|
582
|
-
# Otherwise, go to the database only if none of the following are true:
|
583
|
-
# * target already loaded
|
584
|
-
# * owner is new record
|
585
|
-
# * target contains new or changed record(s)
|
586
|
-
def fetch_first_nth_or_last_using_find?(args)
|
587
|
-
if args.first.is_a?(Hash)
|
588
|
-
true
|
589
|
-
else
|
590
|
-
!(loaded? ||
|
591
|
-
owner.new_record? ||
|
592
|
-
target.any? { |record| record.new_record? || record.changed? })
|
593
|
-
end
|
594
|
-
end
|
595
|
-
|
596
481
|
def include_in_memory?(record)
|
597
482
|
if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
598
483
|
assoc = owner.association(reflection.through_reflection.name)
|
599
484
|
assoc.reader.any? { |source|
|
600
|
-
|
601
|
-
|
485
|
+
target_reflection = source.send(reflection.source_reflection.name)
|
486
|
+
target_reflection.respond_to?(:include?) ? target_reflection.include?(record) : target_reflection == record
|
602
487
|
} || target.include?(record)
|
603
488
|
else
|
604
489
|
target.include?(record)
|
@@ -609,7 +494,7 @@ module ActiveRecord
|
|
609
494
|
# specified, then #find scans the entire collection.
|
610
495
|
def find_by_scan(*args)
|
611
496
|
expects_array = args.first.kind_of?(Array)
|
612
|
-
ids = args.flatten.compact.map
|
497
|
+
ids = args.flatten.compact.map(&:to_s).uniq
|
613
498
|
|
614
499
|
if ids.size == 1
|
615
500
|
id = ids.first
|
@@ -619,16 +504,6 @@ module ActiveRecord
|
|
619
504
|
load_target.select { |r| ids.include?(r.id.to_s) }
|
620
505
|
end
|
621
506
|
end
|
622
|
-
|
623
|
-
# Fetches the first/last using SQL if possible, otherwise from the target array.
|
624
|
-
def first_nth_or_last(type, *args)
|
625
|
-
args.shift if args.first.is_a?(Hash) && args.first.empty?
|
626
|
-
|
627
|
-
collection = fetch_first_nth_or_last_using_find?(args) ? scope : load_target
|
628
|
-
collection.send(type, *args).tap do |record|
|
629
|
-
set_inverse_instance record if record.is_a? ActiveRecord::Base
|
630
|
-
end
|
631
|
-
end
|
632
507
|
end
|
633
508
|
end
|
634
509
|
end
|