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,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/filters"
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
# = Active Record Reflection
|
@@ -7,41 +8,46 @@ module ActiveRecord
|
|
7
8
|
extend ActiveSupport::Concern
|
8
9
|
|
9
10
|
included do
|
10
|
-
class_attribute :_reflections
|
11
|
-
class_attribute :aggregate_reflections
|
12
|
-
self._reflections = {}
|
13
|
-
self.aggregate_reflections = {}
|
11
|
+
class_attribute :_reflections, instance_writer: false, default: {}
|
12
|
+
class_attribute :aggregate_reflections, instance_writer: false, default: {}
|
14
13
|
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
HasManyReflection
|
22
|
-
when :has_one
|
23
|
-
HasOneReflection
|
24
|
-
when :belongs_to
|
25
|
-
BelongsToReflection
|
26
|
-
else
|
27
|
-
raise "Unsupported Macro: #{macro}"
|
28
|
-
end
|
29
|
-
|
30
|
-
reflection = klass.new(name, scope, options, ar)
|
31
|
-
options[:through] ? ThroughReflection.new(reflection) : reflection
|
32
|
-
end
|
15
|
+
class << self
|
16
|
+
def create(macro, name, scope, options, ar)
|
17
|
+
reflection = reflection_class_for(macro).new(name, scope, options, ar)
|
18
|
+
options[:through] ? ThroughReflection.new(reflection) : reflection
|
19
|
+
end
|
33
20
|
|
34
|
-
|
35
|
-
|
36
|
-
|
21
|
+
def add_reflection(ar, name, reflection)
|
22
|
+
ar.clear_reflections_cache
|
23
|
+
name = -name.to_s
|
24
|
+
ar._reflections = ar._reflections.except(name).merge!(name => reflection)
|
25
|
+
end
|
37
26
|
|
38
|
-
|
39
|
-
|
27
|
+
def add_aggregate_reflection(ar, name, reflection)
|
28
|
+
ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def reflection_class_for(macro)
|
33
|
+
case macro
|
34
|
+
when :composed_of
|
35
|
+
AggregateReflection
|
36
|
+
when :has_many
|
37
|
+
HasManyReflection
|
38
|
+
when :has_one
|
39
|
+
HasOneReflection
|
40
|
+
when :belongs_to
|
41
|
+
BelongsToReflection
|
42
|
+
else
|
43
|
+
raise "Unsupported Macro: #{macro}"
|
44
|
+
end
|
45
|
+
end
|
40
46
|
end
|
41
47
|
|
42
|
-
# \Reflection enables
|
43
|
-
#
|
44
|
-
#
|
48
|
+
# \Reflection enables the ability to examine the associations and aggregations of
|
49
|
+
# Active Record classes and objects. This information, for example,
|
50
|
+
# can be used in a form builder that takes an Active Record object
|
45
51
|
# and creates input fields for all of the attributes depending on their type
|
46
52
|
# and displays the associations to other objects.
|
47
53
|
#
|
@@ -61,22 +67,27 @@ module ActiveRecord
|
|
61
67
|
aggregate_reflections[aggregation.to_s]
|
62
68
|
end
|
63
69
|
|
64
|
-
# Returns a Hash of name of the reflection as the key and
|
70
|
+
# Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
|
65
71
|
#
|
66
72
|
# Account.reflections # => {"balance" => AggregateReflection}
|
67
73
|
#
|
68
|
-
# @api public
|
69
74
|
def reflections
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
75
|
+
@__reflections ||= begin
|
76
|
+
ref = {}
|
77
|
+
|
78
|
+
_reflections.each do |name, reflection|
|
79
|
+
parent_reflection = reflection.parent_reflection
|
80
|
+
|
81
|
+
if parent_reflection
|
82
|
+
parent_name = parent_reflection.name
|
83
|
+
ref[parent_name.to_s] = parent_reflection
|
84
|
+
else
|
85
|
+
ref[name] = reflection
|
86
|
+
end
|
77
87
|
end
|
88
|
+
|
89
|
+
ref
|
78
90
|
end
|
79
|
-
ref
|
80
91
|
end
|
81
92
|
|
82
93
|
# Returns an array of AssociationReflection objects for all the
|
@@ -89,10 +100,10 @@ module ActiveRecord
|
|
89
100
|
# Account.reflect_on_all_associations # returns an array of all associations
|
90
101
|
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
|
91
102
|
#
|
92
|
-
# @api public
|
93
103
|
def reflect_on_all_associations(macro = nil)
|
94
104
|
association_reflections = reflections.values
|
95
|
-
|
105
|
+
association_reflections.select! { |reflection| reflection.macro == macro } if macro
|
106
|
+
association_reflections
|
96
107
|
end
|
97
108
|
|
98
109
|
# Returns the AssociationReflection object for the +association+ (use the symbol).
|
@@ -100,27 +111,42 @@ module ActiveRecord
|
|
100
111
|
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
101
112
|
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
102
113
|
#
|
103
|
-
# @api public
|
104
114
|
def reflect_on_association(association)
|
105
115
|
reflections[association.to_s]
|
106
116
|
end
|
107
117
|
|
108
|
-
# @api private
|
109
118
|
def _reflect_on_association(association) #:nodoc:
|
110
119
|
_reflections[association.to_s]
|
111
120
|
end
|
112
121
|
|
113
122
|
# Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
|
114
|
-
#
|
115
|
-
# @api public
|
116
123
|
def reflect_on_all_autosave_associations
|
117
124
|
reflections.values.select { |reflection| reflection.options[:autosave] }
|
118
125
|
end
|
126
|
+
|
127
|
+
def clear_reflections_cache # :nodoc:
|
128
|
+
@__reflections = nil
|
129
|
+
end
|
119
130
|
end
|
120
131
|
|
121
|
-
# Holds all the methods that are shared between MacroReflection
|
122
|
-
#
|
132
|
+
# Holds all the methods that are shared between MacroReflection and ThroughReflection.
|
133
|
+
#
|
134
|
+
# AbstractReflection
|
135
|
+
# MacroReflection
|
136
|
+
# AggregateReflection
|
137
|
+
# AssociationReflection
|
138
|
+
# HasManyReflection
|
139
|
+
# HasOneReflection
|
140
|
+
# BelongsToReflection
|
141
|
+
# HasAndBelongsToManyReflection
|
142
|
+
# ThroughReflection
|
143
|
+
# PolymorphicReflection
|
144
|
+
# RuntimeReflection
|
123
145
|
class AbstractReflection # :nodoc:
|
146
|
+
def through_reflection?
|
147
|
+
false
|
148
|
+
end
|
149
|
+
|
124
150
|
def table_name
|
125
151
|
klass.table_name
|
126
152
|
end
|
@@ -131,14 +157,6 @@ module ActiveRecord
|
|
131
157
|
klass.new(attributes, &block)
|
132
158
|
end
|
133
159
|
|
134
|
-
def quoted_table_name
|
135
|
-
klass.quoted_table_name
|
136
|
-
end
|
137
|
-
|
138
|
-
def primary_key_type
|
139
|
-
klass.type_for_attribute(klass.primary_key)
|
140
|
-
end
|
141
|
-
|
142
160
|
# Returns the class name for the macro.
|
143
161
|
#
|
144
162
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
@@ -149,29 +167,163 @@ module ActiveRecord
|
|
149
167
|
|
150
168
|
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
151
169
|
|
152
|
-
def join_keys
|
153
|
-
|
170
|
+
def join_keys
|
171
|
+
@join_keys ||= get_join_keys(klass)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Returns a list of scopes that should be applied for this Reflection
|
175
|
+
# object when querying the database.
|
176
|
+
def scopes
|
177
|
+
scope ? [scope] : []
|
178
|
+
end
|
179
|
+
|
180
|
+
def join_scope(table, foreign_table, foreign_klass)
|
181
|
+
predicate_builder = predicate_builder(table)
|
182
|
+
scope_chain_items = join_scopes(table, predicate_builder)
|
183
|
+
klass_scope = klass_join_scope(table, predicate_builder)
|
184
|
+
|
185
|
+
if type
|
186
|
+
klass_scope.where!(type => foreign_klass.polymorphic_name)
|
187
|
+
end
|
188
|
+
|
189
|
+
scope_chain_items.inject(klass_scope, &:merge!)
|
190
|
+
|
191
|
+
key = join_keys.key
|
192
|
+
foreign_key = join_keys.foreign_key
|
193
|
+
|
194
|
+
klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
|
195
|
+
|
196
|
+
if klass.finder_needs_type_condition?
|
197
|
+
klass_scope.where!(klass.send(:type_condition, table))
|
198
|
+
end
|
199
|
+
|
200
|
+
klass_scope
|
201
|
+
end
|
202
|
+
|
203
|
+
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
204
|
+
if scope
|
205
|
+
[scope_for(build_scope(table, predicate_builder, klass))]
|
206
|
+
else
|
207
|
+
[]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def klass_join_scope(table, predicate_builder) # :nodoc:
|
212
|
+
relation = build_scope(table, predicate_builder)
|
213
|
+
klass.scope_for_association(relation)
|
214
|
+
end
|
215
|
+
|
216
|
+
def constraints
|
217
|
+
chain.flat_map(&:scopes)
|
218
|
+
end
|
219
|
+
|
220
|
+
def counter_cache_column
|
221
|
+
if belongs_to?
|
222
|
+
if options[:counter_cache] == true
|
223
|
+
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
224
|
+
elsif options[:counter_cache]
|
225
|
+
options[:counter_cache].to_s
|
226
|
+
end
|
227
|
+
else
|
228
|
+
options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
|
229
|
+
end
|
154
230
|
end
|
155
231
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
232
|
+
def inverse_of
|
233
|
+
return unless inverse_name
|
234
|
+
|
235
|
+
@inverse_of ||= klass._reflect_on_association inverse_name
|
236
|
+
end
|
237
|
+
|
238
|
+
def check_validity_of_inverse!
|
239
|
+
unless polymorphic?
|
240
|
+
if has_inverse? && inverse_of.nil?
|
241
|
+
raise InverseOfAssociationNotFoundError.new(self)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# This shit is nasty. We need to avoid the following situation:
|
247
|
+
#
|
248
|
+
# * An associated record is deleted via record.destroy
|
249
|
+
# * Hence the callbacks run, and they find a belongs_to on the record with a
|
250
|
+
# :counter_cache options which points back at our owner. So they update the
|
251
|
+
# counter cache.
|
252
|
+
# * In which case, we must make sure to *not* update the counter cache, or else
|
253
|
+
# it will be decremented twice.
|
254
|
+
#
|
255
|
+
# Hence this method.
|
256
|
+
def inverse_which_updates_counter_cache
|
257
|
+
return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
|
258
|
+
@inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
|
259
|
+
inverse.counter_cache_column == counter_cache_column
|
260
|
+
end
|
261
|
+
end
|
262
|
+
alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
|
161
263
|
|
162
|
-
|
264
|
+
def inverse_updates_counter_in_memory?
|
265
|
+
inverse_of && inverse_which_updates_counter_cache == inverse_of
|
163
266
|
end
|
267
|
+
|
268
|
+
# Returns whether a counter cache should be used for this association.
|
269
|
+
#
|
270
|
+
# The counter_cache option must be given on either the owner or inverse
|
271
|
+
# association, and the column must be present on the owner.
|
272
|
+
def has_cached_counter?
|
273
|
+
options[:counter_cache] ||
|
274
|
+
inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
|
275
|
+
!!active_record.columns_hash[counter_cache_column]
|
276
|
+
end
|
277
|
+
|
278
|
+
def counter_must_be_updated_by_has_many?
|
279
|
+
!inverse_updates_counter_in_memory? && has_cached_counter?
|
280
|
+
end
|
281
|
+
|
282
|
+
def alias_candidate(name)
|
283
|
+
"#{plural_name}_#{name}"
|
284
|
+
end
|
285
|
+
|
286
|
+
def chain
|
287
|
+
collect_join_chain
|
288
|
+
end
|
289
|
+
|
290
|
+
def get_join_keys(association_klass)
|
291
|
+
JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
|
292
|
+
end
|
293
|
+
|
294
|
+
def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
|
295
|
+
Relation.create(
|
296
|
+
klass,
|
297
|
+
table: table,
|
298
|
+
predicate_builder: predicate_builder
|
299
|
+
)
|
300
|
+
end
|
301
|
+
|
302
|
+
def join_primary_key(*)
|
303
|
+
foreign_key
|
304
|
+
end
|
305
|
+
|
306
|
+
def join_foreign_key
|
307
|
+
active_record_primary_key
|
308
|
+
end
|
309
|
+
|
310
|
+
protected
|
311
|
+
def actual_source_reflection # FIXME: this is a horrible name
|
312
|
+
self
|
313
|
+
end
|
314
|
+
|
315
|
+
private
|
316
|
+
def predicate_builder(table)
|
317
|
+
PredicateBuilder.new(TableMetadata.new(klass, table))
|
318
|
+
end
|
319
|
+
|
320
|
+
def primary_key(klass)
|
321
|
+
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
322
|
+
end
|
164
323
|
end
|
324
|
+
|
165
325
|
# Base class for AggregateReflection and AssociationReflection. Objects of
|
166
326
|
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
167
|
-
#
|
168
|
-
# MacroReflection
|
169
|
-
# AssociationReflection
|
170
|
-
# AggregateReflection
|
171
|
-
# HasManyReflection
|
172
|
-
# HasOneReflection
|
173
|
-
# BelongsToReflection
|
174
|
-
# ThroughReflection
|
175
327
|
class MacroReflection < AbstractReflection
|
176
328
|
# Returns the name of the macro.
|
177
329
|
#
|
@@ -196,15 +348,14 @@ module ActiveRecord
|
|
196
348
|
@scope = scope
|
197
349
|
@options = options
|
198
350
|
@active_record = active_record
|
199
|
-
@klass = options[:
|
351
|
+
@klass = options[:anonymous_class]
|
200
352
|
@plural_name = active_record.pluralize_table_names ?
|
201
353
|
name.to_s.pluralize : name.to_s
|
202
354
|
end
|
203
355
|
|
204
356
|
def autosave=(autosave)
|
205
|
-
@automatic_inverse_of = false
|
206
357
|
@options[:autosave] = autosave
|
207
|
-
|
358
|
+
parent_reflection = self.parent_reflection
|
208
359
|
if parent_reflection
|
209
360
|
parent_reflection.autosave = autosave
|
210
361
|
end
|
@@ -214,6 +365,17 @@ module ActiveRecord
|
|
214
365
|
#
|
215
366
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
|
216
367
|
# <tt>has_many :clients</tt> returns the Client class
|
368
|
+
#
|
369
|
+
# class Company < ActiveRecord::Base
|
370
|
+
# has_many :clients
|
371
|
+
# end
|
372
|
+
#
|
373
|
+
# Company.reflect_on_association(:clients).klass
|
374
|
+
# # => Client
|
375
|
+
#
|
376
|
+
# <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
|
377
|
+
# a new association object. Use +build_association+ or +create_association+
|
378
|
+
# instead. This allows plugins to hook into association object creation.
|
217
379
|
def klass
|
218
380
|
@klass ||= compute_class(class_name)
|
219
381
|
end
|
@@ -232,14 +394,17 @@ module ActiveRecord
|
|
232
394
|
active_record == other_aggregation.active_record
|
233
395
|
end
|
234
396
|
|
397
|
+
def scope_for(relation, owner = nil)
|
398
|
+
relation.instance_exec(owner, &scope) || relation
|
399
|
+
end
|
400
|
+
|
235
401
|
private
|
236
402
|
def derive_class_name
|
237
403
|
name.to_s.camelize
|
238
404
|
end
|
239
405
|
end
|
240
406
|
|
241
|
-
|
242
|
-
# Holds all the meta-data about an aggregation as it was specified in the
|
407
|
+
# Holds all the metadata about an aggregation as it was specified in the
|
243
408
|
# Active Record class.
|
244
409
|
class AggregateReflection < MacroReflection #:nodoc:
|
245
410
|
def mapping
|
@@ -248,50 +413,36 @@ module ActiveRecord
|
|
248
413
|
end
|
249
414
|
end
|
250
415
|
|
251
|
-
# Holds all the
|
416
|
+
# Holds all the metadata about an association as it was specified in the
|
252
417
|
# Active Record class.
|
253
418
|
class AssociationReflection < MacroReflection #:nodoc:
|
254
|
-
# Returns the target association's class.
|
255
|
-
#
|
256
|
-
# class Author < ActiveRecord::Base
|
257
|
-
# has_many :books
|
258
|
-
# end
|
259
|
-
#
|
260
|
-
# Author.reflect_on_association(:books).klass
|
261
|
-
# # => Book
|
262
|
-
#
|
263
|
-
# <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
|
264
|
-
# a new association object. Use +build_association+ or +create_association+
|
265
|
-
# instead. This allows plugins to hook into association object creation.
|
266
|
-
def klass
|
267
|
-
@klass ||= compute_class(class_name)
|
268
|
-
end
|
269
|
-
|
270
419
|
def compute_class(name)
|
420
|
+
if polymorphic?
|
421
|
+
raise ArgumentError, "Polymorphic associations do not support computing the class."
|
422
|
+
end
|
271
423
|
active_record.send(:compute_type, name)
|
272
424
|
end
|
273
425
|
|
274
426
|
attr_reader :type, :foreign_type
|
275
|
-
attr_accessor :parent_reflection #
|
427
|
+
attr_accessor :parent_reflection # Reflection
|
276
428
|
|
277
429
|
def initialize(name, scope, options, active_record)
|
278
430
|
super
|
279
|
-
@automatic_inverse_of = nil
|
280
431
|
@type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
|
281
|
-
@foreign_type = options[:foreign_type] || "#{name}_type"
|
432
|
+
@foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
|
282
433
|
@constructable = calculate_constructable(macro, options)
|
283
|
-
|
284
|
-
|
434
|
+
|
435
|
+
if options[:class_name] && options[:class_name].class == Class
|
436
|
+
raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
|
437
|
+
end
|
285
438
|
end
|
286
439
|
|
287
|
-
def association_scope_cache(
|
288
|
-
key =
|
440
|
+
def association_scope_cache(klass, owner, &block)
|
441
|
+
key = self
|
289
442
|
if polymorphic?
|
290
443
|
key = [key, owner._read_attribute(@foreign_type)]
|
291
444
|
end
|
292
|
-
|
293
|
-
@association_scope_cache[key] ||= yield
|
294
|
-
}
|
445
|
+
klass.cached_find_by_statement(key, &block)
|
295
446
|
end
|
296
447
|
|
297
448
|
def constructable? # :nodoc:
|
@@ -303,7 +454,7 @@ module ActiveRecord
|
|
303
454
|
end
|
304
455
|
|
305
456
|
def foreign_key
|
306
|
-
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
457
|
+
@foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
|
307
458
|
end
|
308
459
|
|
309
460
|
def association_foreign_key
|
@@ -319,44 +470,25 @@ module ActiveRecord
|
|
319
470
|
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
|
320
471
|
end
|
321
472
|
|
322
|
-
def counter_cache_column
|
323
|
-
if options[:counter_cache] == true
|
324
|
-
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
325
|
-
elsif options[:counter_cache]
|
326
|
-
options[:counter_cache].to_s
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
473
|
def check_validity!
|
331
474
|
check_validity_of_inverse!
|
332
475
|
end
|
333
476
|
|
334
|
-
def check_validity_of_inverse!
|
335
|
-
unless polymorphic?
|
336
|
-
if has_inverse? && inverse_of.nil?
|
337
|
-
raise InverseOfAssociationNotFoundError.new(self)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
477
|
def check_preloadable!
|
343
478
|
return unless scope
|
344
479
|
|
345
|
-
|
346
|
-
|
480
|
+
unless scope.arity == 0
|
481
|
+
raise ArgumentError, <<-MSG.squish
|
347
482
|
The association scope '#{name}' is instance dependent (the scope
|
348
|
-
block takes an argument). Preloading
|
349
|
-
|
350
|
-
passed to the association scope. This will most likely result in
|
351
|
-
broken or incorrect behavior. Joining, Preloading and eager loading
|
352
|
-
of these associations is deprecated and will be removed in the future.
|
483
|
+
block takes an argument). Preloading instance dependent scopes is
|
484
|
+
not supported.
|
353
485
|
MSG
|
354
486
|
end
|
355
487
|
end
|
356
488
|
alias :check_eager_loadable! :check_preloadable!
|
357
489
|
|
358
490
|
def join_id_for(owner) # :nodoc:
|
359
|
-
owner[
|
491
|
+
owner[join_foreign_key]
|
360
492
|
end
|
361
493
|
|
362
494
|
def through_reflection
|
@@ -369,30 +501,28 @@ module ActiveRecord
|
|
369
501
|
|
370
502
|
# A chain of reflections from this one back to the owner. For more see the explanation in
|
371
503
|
# ThroughReflection.
|
372
|
-
def
|
504
|
+
def collect_join_chain
|
373
505
|
[self]
|
374
506
|
end
|
375
507
|
|
508
|
+
# This is for clearing cache on the reflection. Useful for tests that need to compare
|
509
|
+
# SQL queries on associations.
|
510
|
+
def clear_association_scope_cache # :nodoc:
|
511
|
+
klass.initialize_find_by_cache
|
512
|
+
end
|
513
|
+
|
376
514
|
def nested?
|
377
515
|
false
|
378
516
|
end
|
379
517
|
|
380
|
-
|
381
|
-
|
382
|
-
def scope_chain
|
383
|
-
scope ? [[scope]] : [[]]
|
518
|
+
def has_scope?
|
519
|
+
scope
|
384
520
|
end
|
385
521
|
|
386
522
|
def has_inverse?
|
387
523
|
inverse_name
|
388
524
|
end
|
389
525
|
|
390
|
-
def inverse_of
|
391
|
-
return unless inverse_name
|
392
|
-
|
393
|
-
@inverse_of ||= klass._reflect_on_association inverse_name
|
394
|
-
end
|
395
|
-
|
396
526
|
def polymorphic_inverse_of(associated_class)
|
397
527
|
if has_inverse?
|
398
528
|
if inverse_relationship = associated_class._reflect_on_association(options[:inverse_of])
|
@@ -434,72 +564,51 @@ module ActiveRecord
|
|
434
564
|
# Returns +true+ if +self+ is a +has_one+ reflection.
|
435
565
|
def has_one?; false; end
|
436
566
|
|
437
|
-
def association_class
|
438
|
-
case macro
|
439
|
-
when :belongs_to
|
440
|
-
if polymorphic?
|
441
|
-
Associations::BelongsToPolymorphicAssociation
|
442
|
-
else
|
443
|
-
Associations::BelongsToAssociation
|
444
|
-
end
|
445
|
-
when :has_many
|
446
|
-
if options[:through]
|
447
|
-
Associations::HasManyThroughAssociation
|
448
|
-
else
|
449
|
-
Associations::HasManyAssociation
|
450
|
-
end
|
451
|
-
when :has_one
|
452
|
-
if options[:through]
|
453
|
-
Associations::HasOneThroughAssociation
|
454
|
-
else
|
455
|
-
Associations::HasOneAssociation
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|
567
|
+
def association_class; raise NotImplementedError; end
|
459
568
|
|
460
569
|
def polymorphic?
|
461
570
|
options[:polymorphic]
|
462
571
|
end
|
463
572
|
|
464
573
|
VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
|
465
|
-
INVALID_AUTOMATIC_INVERSE_OPTIONS = [:
|
574
|
+
INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
|
466
575
|
|
467
|
-
|
576
|
+
def add_as_source(seed)
|
577
|
+
seed
|
578
|
+
end
|
468
579
|
|
469
|
-
|
470
|
-
|
471
|
-
|
580
|
+
def add_as_polymorphic_through(reflection, seed)
|
581
|
+
seed + [PolymorphicReflection.new(self, reflection)]
|
582
|
+
end
|
472
583
|
|
473
|
-
|
584
|
+
def add_as_through(seed)
|
585
|
+
seed + [self]
|
586
|
+
end
|
474
587
|
|
588
|
+
def extensions
|
589
|
+
Array(options[:extend])
|
590
|
+
end
|
591
|
+
|
592
|
+
private
|
475
593
|
def calculate_constructable(macro, options)
|
476
|
-
|
477
|
-
when :belongs_to
|
478
|
-
!polymorphic?
|
479
|
-
when :has_one
|
480
|
-
!options[:through]
|
481
|
-
else
|
482
|
-
true
|
483
|
-
end
|
594
|
+
true
|
484
595
|
end
|
485
596
|
|
486
597
|
# Attempts to find the inverse association name automatically.
|
487
598
|
# If it cannot find a suitable inverse association name, it returns
|
488
|
-
# nil
|
599
|
+
# +nil+.
|
489
600
|
def inverse_name
|
490
|
-
|
491
|
-
|
492
|
-
nil
|
493
|
-
else
|
494
|
-
@automatic_inverse_of ||= automatic_inverse_of
|
495
|
-
end
|
601
|
+
unless defined?(@inverse_name)
|
602
|
+
@inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
|
496
603
|
end
|
604
|
+
|
605
|
+
@inverse_name
|
497
606
|
end
|
498
607
|
|
499
|
-
# returns either nil or the inverse association name that it finds.
|
608
|
+
# returns either +nil+ or the inverse association name that it finds.
|
500
609
|
def automatic_inverse_of
|
501
610
|
if can_find_inverse_of_automatically?(self)
|
502
|
-
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name).to_sym
|
611
|
+
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
|
503
612
|
|
504
613
|
begin
|
505
614
|
reflection = klass._reflect_on_association(inverse_name)
|
@@ -510,23 +619,18 @@ module ActiveRecord
|
|
510
619
|
end
|
511
620
|
|
512
621
|
if valid_inverse_reflection?(reflection)
|
513
|
-
|
622
|
+
inverse_name
|
514
623
|
end
|
515
624
|
end
|
516
|
-
|
517
|
-
false
|
518
625
|
end
|
519
626
|
|
520
627
|
# Checks if the inverse reflection that is returned from the
|
521
628
|
# +automatic_inverse_of+ method is a valid reflection. We must
|
522
629
|
# make sure that the reflection's active_record name matches up
|
523
630
|
# with the current reflection's klass name.
|
524
|
-
#
|
525
|
-
# Note: klass will always be valid because when there's a NameError
|
526
|
-
# from calling +klass+, +reflection+ will already be set to false.
|
527
631
|
def valid_inverse_reflection?(reflection)
|
528
632
|
reflection &&
|
529
|
-
klass
|
633
|
+
klass <= reflection.active_record &&
|
530
634
|
can_find_inverse_of_automatically?(reflection)
|
531
635
|
end
|
532
636
|
|
@@ -534,9 +638,8 @@ module ActiveRecord
|
|
534
638
|
# us from being able to guess the inverse automatically. First, the
|
535
639
|
# <tt>inverse_of</tt> option cannot be set to false. Second, we must
|
536
640
|
# have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
|
537
|
-
# Third, we must not have options such as <tt>:
|
538
|
-
#
|
539
|
-
# inverse association.
|
641
|
+
# Third, we must not have options such as <tt>:foreign_key</tt>
|
642
|
+
# which prevent us from correctly guessing the inverse association.
|
540
643
|
#
|
541
644
|
# Anything with a scope can additionally ruin our attempt at finding an
|
542
645
|
# inverse, so we exclude reflections with scopes.
|
@@ -566,56 +669,77 @@ module ActiveRecord
|
|
566
669
|
def derive_join_table
|
567
670
|
ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
|
568
671
|
end
|
569
|
-
|
570
|
-
def primary_key(klass)
|
571
|
-
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
572
|
-
end
|
573
672
|
end
|
574
673
|
|
575
674
|
class HasManyReflection < AssociationReflection # :nodoc:
|
576
|
-
def initialize(name, scope, options, active_record)
|
577
|
-
super(name, scope, options, active_record)
|
578
|
-
end
|
579
|
-
|
580
675
|
def macro; :has_many; end
|
581
676
|
|
582
677
|
def collection?; true; end
|
583
|
-
end
|
584
678
|
|
585
|
-
|
586
|
-
|
587
|
-
|
679
|
+
def association_class
|
680
|
+
if options[:through]
|
681
|
+
Associations::HasManyThroughAssociation
|
682
|
+
else
|
683
|
+
Associations::HasManyAssociation
|
684
|
+
end
|
588
685
|
end
|
589
686
|
|
687
|
+
def association_primary_key(klass = nil)
|
688
|
+
primary_key(klass || self.klass)
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
class HasOneReflection < AssociationReflection # :nodoc:
|
590
693
|
def macro; :has_one; end
|
591
694
|
|
592
695
|
def has_one?; true; end
|
593
|
-
end
|
594
696
|
|
595
|
-
|
596
|
-
|
597
|
-
|
697
|
+
def association_class
|
698
|
+
if options[:through]
|
699
|
+
Associations::HasOneThroughAssociation
|
700
|
+
else
|
701
|
+
Associations::HasOneAssociation
|
702
|
+
end
|
598
703
|
end
|
599
704
|
|
705
|
+
private
|
706
|
+
def calculate_constructable(macro, options)
|
707
|
+
!options[:through]
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
class BelongsToReflection < AssociationReflection # :nodoc:
|
600
712
|
def macro; :belongs_to; end
|
601
713
|
|
602
714
|
def belongs_to?; true; end
|
603
715
|
|
604
|
-
def
|
605
|
-
|
606
|
-
|
716
|
+
def association_class
|
717
|
+
if polymorphic?
|
718
|
+
Associations::BelongsToPolymorphicAssociation
|
719
|
+
else
|
720
|
+
Associations::BelongsToAssociation
|
721
|
+
end
|
607
722
|
end
|
608
723
|
|
609
|
-
def
|
610
|
-
|
724
|
+
def join_primary_key(klass = nil)
|
725
|
+
polymorphic? ? association_primary_key(klass) : association_primary_key
|
611
726
|
end
|
612
|
-
end
|
613
727
|
|
614
|
-
|
615
|
-
|
616
|
-
super
|
728
|
+
def join_foreign_key
|
729
|
+
foreign_key
|
617
730
|
end
|
618
731
|
|
732
|
+
private
|
733
|
+
def can_find_inverse_of_automatically?(_)
|
734
|
+
!polymorphic? && super
|
735
|
+
end
|
736
|
+
|
737
|
+
def calculate_constructable(macro, options)
|
738
|
+
!polymorphic?
|
739
|
+
end
|
740
|
+
end
|
741
|
+
|
742
|
+
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
|
619
743
|
def macro; :has_and_belongs_to_many; end
|
620
744
|
|
621
745
|
def collection?
|
@@ -623,19 +747,22 @@ module ActiveRecord
|
|
623
747
|
end
|
624
748
|
end
|
625
749
|
|
626
|
-
# Holds all the
|
750
|
+
# Holds all the metadata about a :through association as it was specified
|
627
751
|
# in the Active Record class.
|
628
752
|
class ThroughReflection < AbstractReflection #:nodoc:
|
629
|
-
|
630
|
-
|
631
|
-
:active_record_primary_key, :type, :to => :source_reflection
|
753
|
+
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
|
754
|
+
:active_record_primary_key, :type, :get_join_keys, to: :source_reflection
|
632
755
|
|
633
756
|
def initialize(delegate_reflection)
|
634
757
|
@delegate_reflection = delegate_reflection
|
635
|
-
@klass
|
758
|
+
@klass = delegate_reflection.options[:anonymous_class]
|
636
759
|
@source_reflection_name = delegate_reflection.options[:source]
|
637
760
|
end
|
638
761
|
|
762
|
+
def through_reflection?
|
763
|
+
true
|
764
|
+
end
|
765
|
+
|
639
766
|
def klass
|
640
767
|
@klass ||= delegate_reflection.compute_class(class_name)
|
641
768
|
end
|
@@ -694,74 +821,35 @@ module ActiveRecord
|
|
694
821
|
# # => [<ActiveRecord::Reflection::ThroughReflection: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
|
695
822
|
# <ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
|
696
823
|
#
|
697
|
-
def
|
698
|
-
|
699
|
-
a = source_reflection.chain
|
700
|
-
b = through_reflection.chain
|
701
|
-
chain = a + b
|
702
|
-
chain[0] = self # Use self so we don't lose the information from :source_type
|
703
|
-
chain
|
704
|
-
end
|
824
|
+
def collect_join_chain
|
825
|
+
collect_join_reflections [self]
|
705
826
|
end
|
706
827
|
|
707
|
-
#
|
708
|
-
#
|
709
|
-
#
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
#
|
714
|
-
# class Article
|
715
|
-
# has_many :comments
|
716
|
-
# has_many :comment_tags, through: :comments, source: :tags
|
717
|
-
# end
|
718
|
-
#
|
719
|
-
# class Comment
|
720
|
-
# has_many :tags
|
721
|
-
# end
|
722
|
-
#
|
723
|
-
# There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags,
|
724
|
-
# but only Comment.tags will be represented in the #chain. So this method creates an array
|
725
|
-
# of scopes corresponding to the chain.
|
726
|
-
def scope_chain
|
727
|
-
@scope_chain ||= begin
|
728
|
-
scope_chain = source_reflection.scope_chain.map(&:dup)
|
729
|
-
|
730
|
-
# Add to it the scope from this reflection (if any)
|
731
|
-
scope_chain.first << scope if scope
|
732
|
-
|
733
|
-
through_scope_chain = through_reflection.scope_chain.map(&:dup)
|
734
|
-
|
735
|
-
if options[:source_type]
|
736
|
-
type = foreign_type
|
737
|
-
source_type = options[:source_type]
|
738
|
-
through_scope_chain.first << lambda { |object|
|
739
|
-
where(type => source_type)
|
740
|
-
}
|
741
|
-
end
|
742
|
-
|
743
|
-
# Recursively fill out the rest of the array from the through reflection
|
744
|
-
scope_chain + through_scope_chain
|
745
|
-
end
|
828
|
+
# This is for clearing cache on the reflection. Useful for tests that need to compare
|
829
|
+
# SQL queries on associations.
|
830
|
+
def clear_association_scope_cache # :nodoc:
|
831
|
+
delegate_reflection.clear_association_scope_cache
|
832
|
+
source_reflection.clear_association_scope_cache
|
833
|
+
through_reflection.clear_association_scope_cache
|
746
834
|
end
|
747
835
|
|
748
|
-
def
|
749
|
-
source_reflection.
|
836
|
+
def scopes
|
837
|
+
source_reflection.scopes + super
|
750
838
|
end
|
751
839
|
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
ActiveRecord::Base.source_macro is deprecated and will be removed
|
756
|
-
without replacement.
|
757
|
-
MSG
|
840
|
+
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
841
|
+
source_reflection.join_scopes(table, predicate_builder, klass) + super
|
842
|
+
end
|
758
843
|
|
759
|
-
|
844
|
+
def has_scope?
|
845
|
+
scope || options[:source_type] ||
|
846
|
+
source_reflection.has_scope? ||
|
847
|
+
through_reflection.has_scope?
|
760
848
|
end
|
761
849
|
|
762
850
|
# A through association is nested if there would be more than one join table
|
763
851
|
def nested?
|
764
|
-
|
852
|
+
source_reflection.through_reflection? || through_reflection.through_reflection?
|
765
853
|
end
|
766
854
|
|
767
855
|
# We want to use the klass from this reflection, rather than just delegate straight to
|
@@ -791,21 +879,19 @@ module ActiveRecord
|
|
791
879
|
def source_reflection_name # :nodoc:
|
792
880
|
return @source_reflection_name if @source_reflection_name
|
793
881
|
|
794
|
-
names = [name.to_s.singularize, name].collect
|
882
|
+
names = [name.to_s.singularize, name].collect(&:to_sym).uniq
|
795
883
|
names = names.find_all { |n|
|
796
884
|
through_reflection.klass._reflect_on_association(n)
|
797
885
|
}
|
798
886
|
|
799
887
|
if names.length > 1
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
" #{macro} :#{name}, #{example_options}\n" \
|
808
|
-
" end"
|
888
|
+
raise AmbiguousSourceReflectionForThroughAssociation.new(
|
889
|
+
active_record.name,
|
890
|
+
macro,
|
891
|
+
name,
|
892
|
+
options,
|
893
|
+
source_reflection_names
|
894
|
+
)
|
809
895
|
end
|
810
896
|
|
811
897
|
@source_reflection_name = names.first
|
@@ -819,10 +905,6 @@ module ActiveRecord
|
|
819
905
|
through_reflection.options
|
820
906
|
end
|
821
907
|
|
822
|
-
def join_id_for(owner) # :nodoc:
|
823
|
-
source_reflection.join_id_for(owner)
|
824
|
-
end
|
825
|
-
|
826
908
|
def check_validity!
|
827
909
|
if through_reflection.nil?
|
828
910
|
raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
|
@@ -852,20 +934,54 @@ module ActiveRecord
|
|
852
934
|
raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
|
853
935
|
end
|
854
936
|
|
937
|
+
if parent_reflection.nil?
|
938
|
+
reflections = active_record.reflections.keys.map(&:to_sym)
|
939
|
+
|
940
|
+
if reflections.index(through_reflection.name) > reflections.index(name)
|
941
|
+
raise HasManyThroughOrderError.new(active_record.name, self, through_reflection)
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
855
945
|
check_validity_of_inverse!
|
856
946
|
end
|
857
947
|
|
858
|
-
|
948
|
+
def constraints
|
949
|
+
scope_chain = source_reflection.constraints
|
950
|
+
scope_chain << scope if scope
|
951
|
+
scope_chain
|
952
|
+
end
|
859
953
|
|
954
|
+
def add_as_source(seed)
|
955
|
+
collect_join_reflections seed
|
956
|
+
end
|
957
|
+
|
958
|
+
def add_as_polymorphic_through(reflection, seed)
|
959
|
+
collect_join_reflections(seed + [PolymorphicReflection.new(self, reflection)])
|
960
|
+
end
|
961
|
+
|
962
|
+
def add_as_through(seed)
|
963
|
+
collect_join_reflections(seed + [self])
|
964
|
+
end
|
965
|
+
|
966
|
+
protected
|
860
967
|
def actual_source_reflection # FIXME: this is a horrible name
|
861
|
-
source_reflection.
|
968
|
+
source_reflection.actual_source_reflection
|
862
969
|
end
|
863
970
|
|
864
|
-
|
865
|
-
|
971
|
+
private
|
972
|
+
attr_reader :delegate_reflection
|
973
|
+
|
974
|
+
def collect_join_reflections(seed)
|
975
|
+
a = source_reflection.add_as_source seed
|
976
|
+
if options[:source_type]
|
977
|
+
through_reflection.add_as_polymorphic_through self, a
|
978
|
+
else
|
979
|
+
through_reflection.add_as_through a
|
980
|
+
end
|
866
981
|
end
|
867
982
|
|
868
|
-
|
983
|
+
def inverse_name; delegate_reflection.send(:inverse_name); end
|
984
|
+
|
869
985
|
def derive_class_name
|
870
986
|
# get the class_name of the belongs_to association of the through reflection
|
871
987
|
options[:source_type] || source_reflection.class_name
|
@@ -875,7 +991,50 @@ module ActiveRecord
|
|
875
991
|
public_instance_methods
|
876
992
|
|
877
993
|
delegate(*delegate_methods, to: :delegate_reflection)
|
994
|
+
end
|
995
|
+
|
996
|
+
class PolymorphicReflection < AbstractReflection # :nodoc:
|
997
|
+
delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
|
998
|
+
|
999
|
+
def initialize(reflection, previous_reflection)
|
1000
|
+
@reflection = reflection
|
1001
|
+
@previous_reflection = previous_reflection
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
1005
|
+
scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
|
1006
|
+
scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
def constraints
|
1010
|
+
@reflection.constraints + [source_type_scope]
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
private
|
1014
|
+
def source_type_scope
|
1015
|
+
type = @previous_reflection.foreign_type
|
1016
|
+
source_type = @previous_reflection.options[:source_type]
|
1017
|
+
lambda { |object| where(type => source_type) }
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
class RuntimeReflection < AbstractReflection # :nodoc:
|
1022
|
+
delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
|
1023
|
+
|
1024
|
+
def initialize(reflection, association)
|
1025
|
+
@reflection = reflection
|
1026
|
+
@association = association
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
def klass
|
1030
|
+
@association.klass
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
def aliased_table
|
1034
|
+
@aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
|
1035
|
+
end
|
878
1036
|
|
1037
|
+
def all_includes; yield; end
|
879
1038
|
end
|
880
1039
|
end
|
881
1040
|
end
|