activerecord 4.2.9 → 6.1.4.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 +964 -1382
- data/MIT-LICENSE +4 -2
- data/README.rdoc +15 -14
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +266 -251
- data/lib/active_record/association_relation.rb +40 -15
- data/lib/active_record/associations/alias_tracker.rb +40 -43
- data/lib/active_record/associations/association.rb +162 -69
- data/lib/active_record/associations/association_scope.rb +105 -130
- data/lib/active_record/associations/belongs_to_association.rb +83 -65
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
- data/lib/active_record/associations/builder/association.rb +57 -43
- data/lib/active_record/associations/builder/belongs_to.rb +74 -57
- data/lib/active_record/associations/builder/collection_association.rb +15 -37
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +49 -66
- data/lib/active_record/associations/builder/has_many.rb +13 -5
- data/lib/active_record/associations/builder/has_one.rb +44 -6
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +148 -287
- data/lib/active_record/associations/collection_proxy.rb +252 -150
- data/lib/active_record/associations/foreign_association.rb +23 -1
- data/lib/active_record/associations/has_many_association.rb +56 -98
- data/lib/active_record/associations/has_many_through_association.rb +68 -89
- data/lib/active_record/associations/has_one_association.rb +73 -47
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -81
- 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 +174 -169
- data/lib/active_record/associations/preloader/association.rb +108 -115
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/preloader.rb +97 -94
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +39 -19
- data/lib/active_record/associations.rb +1845 -1598
- data/lib/active_record/attribute_assignment.rb +59 -185
- data/lib/active_record/attribute_methods/before_type_cast.rb +18 -10
- data/lib/active_record/attribute_methods/dirty.rb +168 -148
- data/lib/active_record/attribute_methods/primary_key.rb +93 -83
- data/lib/active_record/attribute_methods/query.rb +8 -10
- data/lib/active_record/attribute_methods/read.rb +19 -79
- data/lib/active_record/attribute_methods/serialization.rb +49 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +55 -36
- data/lib/active_record/attribute_methods/write.rb +24 -55
- data/lib/active_record/attribute_methods.rb +149 -154
- data/lib/active_record/attributes.rb +234 -78
- data/lib/active_record/autosave_association.rb +133 -60
- data/lib/active_record/base.rb +46 -46
- data/lib/active_record/callbacks.rb +234 -79
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +34 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -323
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +292 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +177 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +8 -6
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +473 -255
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +869 -286
- data/lib/active_record/connection_adapters/abstract/transaction.rb +257 -91
- data/lib/active_record/connection_adapters/abstract_adapter.rb +483 -230
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +557 -640
- data/lib/active_record/connection_adapters/column.rb +67 -40
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +194 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +80 -192
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -160
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +49 -58
- 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 +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -19
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
- 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/interval.rb +49 -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/macaddr.rb +25 -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 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
- 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 +25 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +145 -48
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -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 +496 -298
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +588 -375
- data/lib/active_record/connection_adapters/schema_cache.rb +167 -29
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -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 +21 -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 +170 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -373
- data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +314 -41
- data/lib/active_record/core.rb +458 -241
- data/lib/active_record/counter_cache.rb +70 -49
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +87 -106
- data/lib/active_record/enum.rb +211 -92
- data/lib/active_record/errors.rb +224 -54
- data/lib/active_record/explain.rb +27 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +33 -14
- data/lib/active_record/fixture_set/model_metadata.rb +32 -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 +275 -500
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +175 -110
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +121 -29
- data/lib/active_record/internal_metadata.rb +62 -0
- data/lib/active_record/legacy_yaml_adapter.rb +27 -5
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +98 -92
- data/lib/active_record/locking/pessimistic.rb +22 -6
- data/lib/active_record/log_subscriber.rb +93 -31
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +185 -90
- data/lib/active_record/migration/compatibility.rb +295 -0
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/migration.rb +673 -325
- data/lib/active_record/model_schema.rb +418 -113
- data/lib/active_record/nested_attributes.rb +263 -224
- data/lib/active_record/no_touching.rb +15 -2
- data/lib/active_record/null_relation.rb +24 -38
- data/lib/active_record/persistence.rb +572 -136
- data/lib/active_record/query_cache.rb +29 -23
- data/lib/active_record/querying.rb +50 -31
- data/lib/active_record/railtie.rb +170 -51
- data/lib/active_record/railties/console_sandbox.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +523 -199
- data/lib/active_record/readonly_attributes.rb +9 -4
- data/lib/active_record/reflection.rb +454 -291
- data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
- data/lib/active_record/relation/batches.rb +217 -59
- data/lib/active_record/relation/calculations.rb +324 -249
- data/lib/active_record/relation/delegation.rb +76 -84
- data/lib/active_record/relation/finder_methods.rb +316 -242
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +95 -103
- data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -26
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -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 +57 -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 +136 -122
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +757 -413
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -20
- data/lib/active_record/relation/where_clause.rb +239 -0
- data/lib/active_record/relation.rb +554 -343
- data/lib/active_record/result.rb +91 -47
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +134 -122
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +141 -92
- data/lib/active_record/schema_migration.rb +24 -23
- data/lib/active_record/scoping/default.rb +96 -83
- data/lib/active_record/scoping/named.rb +78 -36
- data/lib/active_record/scoping.rb +45 -27
- data/lib/active_record/secure_token.rb +48 -0
- data/lib/active_record/serialization.rb +8 -6
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +89 -36
- data/lib/active_record/store.rb +128 -43
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +81 -0
- data/lib/active_record/tasks/database_tasks.rb +364 -130
- data/lib/active_record/tasks/mysql_database_tasks.rb +67 -113
- data/lib/active_record/tasks/postgresql_database_tasks.rb +86 -49
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +86 -43
- data/lib/active_record/touch_later.rb +65 -0
- data/lib/active_record/transactions.rb +182 -163
- 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 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- 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 +27 -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 +84 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +12 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +63 -56
- data/lib/active_record/validations.rb +39 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +42 -29
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -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 +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -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 +15 -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 +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -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 +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -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 +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -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 +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -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 +43 -37
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -4
- data/lib/rails/generators/active_record/migration.rb +35 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +172 -65
- 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 -163
- data/lib/active_record/attribute_decorators.rb +0 -66
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
- 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 -31
- data/lib/active_record/type/decimal.rb +0 -64
- 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 -59
- 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 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'active_support/core_ext/hash/except'
|
3
|
-
require 'active_support/core_ext/kernel/singleton_class'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
3
|
module ActiveRecord
|
6
4
|
# = Active Record \Named \Scopes
|
@@ -9,7 +7,7 @@ module ActiveRecord
|
|
9
7
|
extend ActiveSupport::Concern
|
10
8
|
|
11
9
|
module ClassMethods
|
12
|
-
# Returns an
|
10
|
+
# Returns an ActiveRecord::Relation scope object.
|
13
11
|
#
|
14
12
|
# posts = Post.all
|
15
13
|
# posts.size # Fires "select count(*) from posts" and returns the count
|
@@ -20,32 +18,49 @@ module ActiveRecord
|
|
20
18
|
# fruits = fruits.limit(10) if limited?
|
21
19
|
#
|
22
20
|
# You can define a scope that applies to all finders using
|
23
|
-
#
|
21
|
+
# {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
|
24
22
|
def all
|
25
|
-
|
26
|
-
|
23
|
+
scope = current_scope
|
24
|
+
|
25
|
+
if scope
|
26
|
+
if self == scope.klass
|
27
|
+
scope.clone
|
28
|
+
else
|
29
|
+
relation.merge!(scope)
|
30
|
+
end
|
27
31
|
else
|
28
32
|
default_scoped
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
32
|
-
def
|
33
|
-
|
36
|
+
def scope_for_association(scope = relation) # :nodoc:
|
37
|
+
if current_scope&.empty_scope?
|
38
|
+
scope
|
39
|
+
else
|
40
|
+
default_scoped(scope)
|
41
|
+
end
|
34
42
|
end
|
35
43
|
|
36
|
-
#
|
37
|
-
|
38
|
-
|
39
|
-
all.scope_for_create
|
44
|
+
# Returns a scope for the model with default scopes.
|
45
|
+
def default_scoped(scope = relation)
|
46
|
+
build_default_scope(scope) || scope
|
40
47
|
end
|
41
48
|
|
42
|
-
|
43
|
-
|
44
|
-
|
49
|
+
def default_extensions # :nodoc:
|
50
|
+
if scope = scope_for_association || build_default_scope
|
51
|
+
scope.extensions
|
52
|
+
else
|
53
|
+
[]
|
54
|
+
end
|
45
55
|
end
|
46
56
|
|
47
|
-
# Adds a class method for retrieving and querying objects.
|
48
|
-
#
|
57
|
+
# Adds a class method for retrieving and querying objects.
|
58
|
+
# The method is intended to return an ActiveRecord::Relation
|
59
|
+
# object, which is composable with other scopes.
|
60
|
+
# If it returns +nil+ or +false+, an
|
61
|
+
# {all}[rdoc-ref:Scoping::Named::ClassMethods#all] scope is returned instead.
|
62
|
+
#
|
63
|
+
# A \scope represents a narrowing of a database query, such as
|
49
64
|
# <tt>where(color: :red).select('shirts.*').includes(:washing_instructions)</tt>.
|
50
65
|
#
|
51
66
|
# class Shirt < ActiveRecord::Base
|
@@ -53,14 +68,10 @@ module ActiveRecord
|
|
53
68
|
# scope :dry_clean_only, -> { joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true) }
|
54
69
|
# end
|
55
70
|
#
|
56
|
-
# The above calls to
|
71
|
+
# The above calls to #scope define class methods <tt>Shirt.red</tt> and
|
57
72
|
# <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, in effect,
|
58
73
|
# represents the query <tt>Shirt.where(color: 'red')</tt>.
|
59
74
|
#
|
60
|
-
# You should always pass a callable object to the scopes defined
|
61
|
-
# with +scope+. This ensures that the scope is re-evaluated each
|
62
|
-
# time it is called.
|
63
|
-
#
|
64
75
|
# Note that this is simply 'syntactic sugar' for defining an actual
|
65
76
|
# class method:
|
66
77
|
#
|
@@ -71,14 +82,15 @@ module ActiveRecord
|
|
71
82
|
# end
|
72
83
|
#
|
73
84
|
# Unlike <tt>Shirt.find(...)</tt>, however, the object returned by
|
74
|
-
# <tt>Shirt.red</tt> is not an Array
|
75
|
-
#
|
76
|
-
#
|
85
|
+
# <tt>Shirt.red</tt> is not an Array but an ActiveRecord::Relation,
|
86
|
+
# which is composable with other scopes; it resembles the association object
|
87
|
+
# constructed by a {has_many}[rdoc-ref:Associations::ClassMethods#has_many]
|
88
|
+
# declaration. For instance, you can invoke <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
|
77
89
|
# <tt>Shirt.red.where(size: 'small')</tt>. Also, just as with the
|
78
90
|
# association objects, named \scopes act like an Array, implementing
|
79
91
|
# Enumerable; <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>,
|
80
92
|
# and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if
|
81
|
-
# <tt>Shirt.red</tt> really was an
|
93
|
+
# <tt>Shirt.red</tt> really was an array.
|
82
94
|
#
|
83
95
|
# These named \scopes are composable. For instance,
|
84
96
|
# <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are
|
@@ -89,7 +101,8 @@ module ActiveRecord
|
|
89
101
|
#
|
90
102
|
# All scopes are available as class methods on the ActiveRecord::Base
|
91
103
|
# descendant upon which the \scopes were defined. But they are also
|
92
|
-
# available to
|
104
|
+
# available to {has_many}[rdoc-ref:Associations::ClassMethods#has_many]
|
105
|
+
# associations. If,
|
93
106
|
#
|
94
107
|
# class Person < ActiveRecord::Base
|
95
108
|
# has_many :shirts
|
@@ -98,8 +111,8 @@ module ActiveRecord
|
|
98
111
|
# then <tt>elton.shirts.red.dry_clean_only</tt> will return all of
|
99
112
|
# Elton's red, dry clean only shirts.
|
100
113
|
#
|
101
|
-
# \Named scopes can also have extensions, just as with
|
102
|
-
# declarations:
|
114
|
+
# \Named scopes can also have extensions, just as with
|
115
|
+
# {has_many}[rdoc-ref:Associations::ClassMethods#has_many] declarations:
|
103
116
|
#
|
104
117
|
# class Shirt < ActiveRecord::Base
|
105
118
|
# scope :red, -> { where(color: 'red') } do
|
@@ -140,7 +153,7 @@ module ActiveRecord
|
|
140
153
|
# Article.featured.titles
|
141
154
|
def scope(name, body, &block)
|
142
155
|
unless body.respond_to?(:call)
|
143
|
-
raise ArgumentError,
|
156
|
+
raise ArgumentError, "The scope body needs to be callable."
|
144
157
|
end
|
145
158
|
|
146
159
|
if dangerous_class_method?(name)
|
@@ -149,15 +162,44 @@ module ActiveRecord
|
|
149
162
|
"a class method with the same name."
|
150
163
|
end
|
151
164
|
|
152
|
-
|
165
|
+
if method_defined_within?(name, Relation)
|
166
|
+
raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
|
167
|
+
"on the model \"#{self.name}\", but ActiveRecord::Relation already defined " \
|
168
|
+
"an instance method with the same name."
|
169
|
+
end
|
153
170
|
|
154
|
-
|
155
|
-
|
156
|
-
scope = scope.extending(extension) if extension
|
171
|
+
valid_scope_name?(name)
|
172
|
+
extension = Module.new(&block) if block
|
157
173
|
|
158
|
-
|
174
|
+
if body.respond_to?(:to_proc)
|
175
|
+
singleton_class.define_method(name) do |*args|
|
176
|
+
scope = all._exec_scope(*args, &body)
|
177
|
+
scope = scope.extending(extension) if extension
|
178
|
+
scope
|
179
|
+
end
|
180
|
+
else
|
181
|
+
singleton_class.define_method(name) do |*args|
|
182
|
+
scope = body.call(*args) || all
|
183
|
+
scope = scope.extending(extension) if extension
|
184
|
+
scope
|
185
|
+
end
|
159
186
|
end
|
187
|
+
singleton_class.send(:ruby2_keywords, name) if respond_to?(:ruby2_keywords, true)
|
188
|
+
|
189
|
+
generate_relation_method(name)
|
160
190
|
end
|
191
|
+
|
192
|
+
private
|
193
|
+
def singleton_method_added(name)
|
194
|
+
generate_relation_method(name) if Kernel.respond_to?(name) && !ActiveRecord::Relation.method_defined?(name)
|
195
|
+
end
|
196
|
+
|
197
|
+
def valid_scope_name?(name)
|
198
|
+
if respond_to?(name, true) && logger
|
199
|
+
logger.warn "Creating scope :#{name}. " \
|
200
|
+
"Overwriting existing method #{self.name}.#{name}."
|
201
|
+
end
|
202
|
+
end
|
161
203
|
end
|
162
204
|
end
|
163
205
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/per_thread_registry"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module Scoping
|
@@ -9,25 +11,35 @@ module ActiveRecord
|
|
9
11
|
include Named
|
10
12
|
end
|
11
13
|
|
12
|
-
module ClassMethods
|
13
|
-
|
14
|
-
|
14
|
+
module ClassMethods # :nodoc:
|
15
|
+
# Collects attributes from scopes that should be applied when creating
|
16
|
+
# an AR instance for the particular class this is called on.
|
17
|
+
def scope_attributes
|
18
|
+
all.scope_for_create
|
19
|
+
end
|
20
|
+
|
21
|
+
# Are there attributes associated with this scope?
|
22
|
+
def scope_attributes?
|
23
|
+
current_scope
|
24
|
+
end
|
25
|
+
|
26
|
+
def current_scope(skip_inherited_scope = false)
|
27
|
+
ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
|
15
28
|
end
|
16
29
|
|
17
|
-
def current_scope=(scope)
|
18
|
-
ScopeRegistry.set_value_for(:current_scope,
|
30
|
+
def current_scope=(scope)
|
31
|
+
ScopeRegistry.set_value_for(:current_scope, self, scope)
|
19
32
|
end
|
20
33
|
end
|
21
34
|
|
22
|
-
def populate_with_current_scope_attributes
|
35
|
+
def populate_with_current_scope_attributes # :nodoc:
|
23
36
|
return unless self.class.scope_attributes?
|
24
37
|
|
25
|
-
self.class.scope_attributes
|
26
|
-
|
27
|
-
end
|
38
|
+
attributes = self.class.scope_attributes
|
39
|
+
_assign_attributes(attributes) if attributes.any?
|
28
40
|
end
|
29
41
|
|
30
|
-
def initialize_internals_callback
|
42
|
+
def initialize_internals_callback # :nodoc:
|
31
43
|
super
|
32
44
|
populate_with_current_scope_attributes
|
33
45
|
end
|
@@ -42,18 +54,18 @@ module ActiveRecord
|
|
42
54
|
# following code:
|
43
55
|
#
|
44
56
|
# registry = ActiveRecord::Scoping::ScopeRegistry
|
45
|
-
# registry.set_value_for(:current_scope,
|
57
|
+
# registry.set_value_for(:current_scope, Board, some_new_scope)
|
46
58
|
#
|
47
59
|
# Now when you run:
|
48
60
|
#
|
49
|
-
# registry.value_for(:current_scope,
|
61
|
+
# registry.value_for(:current_scope, Board)
|
50
62
|
#
|
51
|
-
# You will obtain whatever was defined in +some_new_scope+. The
|
52
|
-
# and
|
63
|
+
# You will obtain whatever was defined in +some_new_scope+. The #value_for
|
64
|
+
# and #set_value_for methods are delegated to the current ScopeRegistry
|
53
65
|
# object, so the above example code can also be called as:
|
54
66
|
#
|
55
67
|
# ActiveRecord::Scoping::ScopeRegistry.set_value_for(:current_scope,
|
56
|
-
#
|
68
|
+
# Board, some_new_scope)
|
57
69
|
class ScopeRegistry # :nodoc:
|
58
70
|
extend ActiveSupport::PerThreadRegistry
|
59
71
|
|
@@ -63,25 +75,31 @@ module ActiveRecord
|
|
63
75
|
@registry = Hash.new { |hash, key| hash[key] = {} }
|
64
76
|
end
|
65
77
|
|
66
|
-
# Obtains the value for a given +
|
67
|
-
def value_for(scope_type,
|
78
|
+
# Obtains the value for a given +scope_type+ and +model+.
|
79
|
+
def value_for(scope_type, model, skip_inherited_scope = false)
|
68
80
|
raise_invalid_scope_type!(scope_type)
|
69
|
-
@registry[scope_type][
|
81
|
+
return @registry[scope_type][model.name] if skip_inherited_scope
|
82
|
+
klass = model
|
83
|
+
base = model.base_class
|
84
|
+
while klass <= base
|
85
|
+
value = @registry[scope_type][klass.name]
|
86
|
+
return value if value
|
87
|
+
klass = klass.superclass
|
88
|
+
end
|
70
89
|
end
|
71
90
|
|
72
|
-
# Sets the +value+ for a given +scope_type+ and +
|
73
|
-
def set_value_for(scope_type,
|
91
|
+
# Sets the +value+ for a given +scope_type+ and +model+.
|
92
|
+
def set_value_for(scope_type, model, value)
|
74
93
|
raise_invalid_scope_type!(scope_type)
|
75
|
-
@registry[scope_type][
|
94
|
+
@registry[scope_type][model.name] = value
|
76
95
|
end
|
77
96
|
|
78
97
|
private
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
98
|
+
def raise_invalid_scope_type!(scope_type)
|
99
|
+
if !VALID_SCOPE_TYPES.include?(scope_type)
|
100
|
+
raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
|
101
|
+
end
|
83
102
|
end
|
84
|
-
end
|
85
103
|
end
|
86
104
|
end
|
87
105
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module SecureToken
|
5
|
+
class MinimumLengthError < StandardError; end
|
6
|
+
|
7
|
+
MINIMUM_TOKEN_LENGTH = 24
|
8
|
+
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
# Example using #has_secure_token
|
13
|
+
#
|
14
|
+
# # Schema: User(token:string, auth_token:string)
|
15
|
+
# class User < ActiveRecord::Base
|
16
|
+
# has_secure_token
|
17
|
+
# has_secure_token :auth_token, length: 36
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# user = User.new
|
21
|
+
# user.save
|
22
|
+
# user.token # => "pX27zsMN2ViQKta1bGfLmVJE"
|
23
|
+
# user.auth_token # => "tU9bLuZseefXQ4yQxQo8wjtBvsAfPc78os6R"
|
24
|
+
# user.regenerate_token # => true
|
25
|
+
# user.regenerate_auth_token # => true
|
26
|
+
#
|
27
|
+
# <tt>SecureRandom::base58</tt> is used to generate at minimum a 24-character unique token, so collisions are highly unlikely.
|
28
|
+
#
|
29
|
+
# Note that it's still possible to generate a race condition in the database in the same way that
|
30
|
+
# {validates_uniqueness_of}[rdoc-ref:Validations::ClassMethods#validates_uniqueness_of] can.
|
31
|
+
# You're encouraged to add a unique index in the database to deal with this even more unlikely scenario.
|
32
|
+
def has_secure_token(attribute = :token, length: MINIMUM_TOKEN_LENGTH)
|
33
|
+
if length < MINIMUM_TOKEN_LENGTH
|
34
|
+
raise MinimumLengthError, "Token requires a minimum length of #{MINIMUM_TOKEN_LENGTH} characters."
|
35
|
+
end
|
36
|
+
|
37
|
+
# Load securerandom only when has_secure_token is used.
|
38
|
+
require "active_support/core_ext/securerandom"
|
39
|
+
define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token(length: length) }
|
40
|
+
before_create { send("#{attribute}=", self.class.generate_unique_secure_token(length: length)) unless send("#{attribute}?") }
|
41
|
+
end
|
42
|
+
|
43
|
+
def generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH)
|
44
|
+
SecureRandom.base58(length)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord #:nodoc:
|
2
|
-
# = Active Record Serialization
|
4
|
+
# = Active Record \Serialization
|
3
5
|
module Serialization
|
4
6
|
extend ActiveSupport::Concern
|
5
7
|
include ActiveModel::Serializers::JSON
|
@@ -9,14 +11,14 @@ module ActiveRecord #:nodoc:
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def serializable_hash(options = nil)
|
12
|
-
|
14
|
+
if self.class._has_attribute?(self.class.inheritance_column)
|
15
|
+
options = options ? options.dup : {}
|
13
16
|
|
14
|
-
|
15
|
-
|
17
|
+
options[:except] = Array(options[:except]).map(&:to_s)
|
18
|
+
options[:except] |= Array(self.class.inheritance_column)
|
19
|
+
end
|
16
20
|
|
17
21
|
super(options)
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
21
|
-
|
22
|
-
require 'active_record/serializers/xml_serializer'
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# = Active Record Signed Id
|
5
|
+
module SignedId
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
##
|
10
|
+
# :singleton-method:
|
11
|
+
# Set the secret used for the signed id verifier instance when using Active Record outside of Rails.
|
12
|
+
# Within Rails, this is automatically set using the Rails application key generator.
|
13
|
+
mattr_accessor :signed_id_verifier_secret, instance_writer: false
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
# Lets you find a record based on a signed id that's safe to put into the world without risk of tampering.
|
18
|
+
# This is particularly useful for things like password reset or email verification, where you want
|
19
|
+
# the bearer of the signed id to be able to interact with the underlying record, but usually only within
|
20
|
+
# a certain time period.
|
21
|
+
#
|
22
|
+
# You set the time period that the signed id is valid for during generation, using the instance method
|
23
|
+
# <tt>signed_id(expires_in: 15.minutes)</tt>. If the time has elapsed before a signed find is attempted,
|
24
|
+
# the signed id will no longer be valid, and nil is returned.
|
25
|
+
#
|
26
|
+
# It's possible to further restrict the use of a signed id with a purpose. This helps when you have a
|
27
|
+
# general base model, like a User, which might have signed ids for several things, like password reset
|
28
|
+
# or email verification. The purpose that was set during generation must match the purpose set when
|
29
|
+
# finding. If there's a mismatch, nil is again returned.
|
30
|
+
#
|
31
|
+
# ==== Examples
|
32
|
+
#
|
33
|
+
# signed_id = User.first.signed_id expires_in: 15.minutes, purpose: :password_reset
|
34
|
+
#
|
35
|
+
# User.find_signed signed_id # => nil, since the purpose does not match
|
36
|
+
#
|
37
|
+
# travel 16.minutes
|
38
|
+
# User.find_signed signed_id, purpose: :password_reset # => nil, since the signed id has expired
|
39
|
+
#
|
40
|
+
# travel_back
|
41
|
+
# User.find_signed signed_id, purpose: :password_reset # => User.first
|
42
|
+
def find_signed(signed_id, purpose: nil)
|
43
|
+
raise UnknownPrimaryKey.new(self) if primary_key.nil?
|
44
|
+
|
45
|
+
if id = signed_id_verifier.verified(signed_id, purpose: combine_signed_id_purposes(purpose))
|
46
|
+
find_by primary_key => id
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Works like +find_signed+, but will raise an +ActiveSupport::MessageVerifier::InvalidSignature+
|
51
|
+
# exception if the +signed_id+ has either expired, has a purpose mismatch, is for another record,
|
52
|
+
# or has been tampered with. It will also raise an +ActiveRecord::RecordNotFound+ exception if
|
53
|
+
# the valid signed id can't find a record.
|
54
|
+
#
|
55
|
+
# === Examples
|
56
|
+
#
|
57
|
+
# User.find_signed! "bad data" # => ActiveSupport::MessageVerifier::InvalidSignature
|
58
|
+
#
|
59
|
+
# signed_id = User.first.signed_id
|
60
|
+
# User.first.destroy
|
61
|
+
# User.find_signed! signed_id # => ActiveRecord::RecordNotFound
|
62
|
+
def find_signed!(signed_id, purpose: nil)
|
63
|
+
if id = signed_id_verifier.verify(signed_id, purpose: combine_signed_id_purposes(purpose))
|
64
|
+
find(id)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# The verifier instance that all signed ids are generated and verified from. By default, it'll be initialized
|
69
|
+
# with the class-level +signed_id_verifier_secret+, which within Rails comes from the
|
70
|
+
# Rails.application.key_generator. By default, it's SHA256 for the digest and JSON for the serialization.
|
71
|
+
def signed_id_verifier
|
72
|
+
@signed_id_verifier ||= begin
|
73
|
+
secret = signed_id_verifier_secret
|
74
|
+
secret = secret.call if secret.respond_to?(:call)
|
75
|
+
|
76
|
+
if secret.nil?
|
77
|
+
raise ArgumentError, "You must set ActiveRecord::Base.signed_id_verifier_secret to use signed ids"
|
78
|
+
else
|
79
|
+
ActiveSupport::MessageVerifier.new secret, digest: "SHA256", serializer: JSON
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Allows you to pass in a custom verifier used for the signed ids. This also allows you to use different
|
85
|
+
# verifiers for different classes. This is also helpful if you need to rotate keys, as you can prepare
|
86
|
+
# your custom verifier for that in advance. See +ActiveSupport::MessageVerifier+ for details.
|
87
|
+
def signed_id_verifier=(verifier)
|
88
|
+
@signed_id_verifier = verifier
|
89
|
+
end
|
90
|
+
|
91
|
+
# :nodoc:
|
92
|
+
def combine_signed_id_purposes(purpose)
|
93
|
+
[ base_class.name.underscore, purpose.to_s ].compact_blank.join("/")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
# Returns a signed id that's generated using a preconfigured +ActiveSupport::MessageVerifier+ instance.
|
99
|
+
# This signed id is tamper proof, so it's safe to send in an email or otherwise share with the outside world.
|
100
|
+
# It can further more be set to expire (the default is not to expire), and scoped down with a specific purpose.
|
101
|
+
# If the expiration date has been exceeded before +find_signed+ is called, the id won't find the designated
|
102
|
+
# record. If a purpose is set, this too must match.
|
103
|
+
#
|
104
|
+
# If you accidentally let a signed id out in the wild that you wish to retract sooner than its expiration date
|
105
|
+
# (or maybe you forgot to set an expiration date while meaning to!), you can use the purpose to essentially
|
106
|
+
# version the signed_id, like so:
|
107
|
+
#
|
108
|
+
# user.signed_id purpose: :v2
|
109
|
+
#
|
110
|
+
# And you then change your +find_signed+ calls to require this new purpose. Any old signed ids that were not
|
111
|
+
# created with the purpose will no longer find the record.
|
112
|
+
def signed_id(expires_in: nil, purpose: nil)
|
113
|
+
self.class.signed_id_verifier.generate id, expires_in: expires_in, purpose: self.class.combine_signed_id_purposes(purpose)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|