activerecord 5.2.8.1 → 6.1.6.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 +4 -4
- data/CHANGELOG.md +1255 -596
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +9 -8
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +100 -41
- data/lib/active_record/associations/association_scope.rb +23 -21
- data/lib/active_record/associations/belongs_to_association.rb +55 -48
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
- data/lib/active_record/associations/builder/association.rb +45 -22
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +8 -17
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +44 -34
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +24 -18
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +69 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +47 -34
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +137 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +46 -9
- data/lib/active_record/autosave_association.rb +57 -42
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
- data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- 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 +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- 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 +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
- data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +293 -33
- data/lib/active_record/core.rb +333 -98
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -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 +273 -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 +3 -4
- data/lib/active_record/enum.rb +108 -36
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- 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 +200 -481
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +212 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +28 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +37 -23
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +35 -35
- 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 +96 -44
- data/lib/active_record/migration/compatibility.rb +145 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +206 -157
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +116 -59
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +411 -80
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +109 -93
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -90
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +64 -39
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +62 -45
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +476 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +115 -62
- data/lib/active_record/relation.rb +379 -115
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +4 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +49 -6
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -43
- data/lib/active_record/tasks/database_tasks.rb +277 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +287 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +62 -118
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- 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 +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- 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 +10 -1
- metadata +116 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -11,21 +11,15 @@ module ActiveRecord
|
|
11
11
|
|
12
12
|
module ClassMethods # :nodoc:
|
13
13
|
private
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
#{sync_with_transaction_state}
|
24
|
-
_write_attribute(name, value)
|
25
|
-
end
|
26
|
-
alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
|
27
|
-
undef_method :__temp__#{safe_name}=
|
28
|
-
STR
|
14
|
+
def define_method_attribute=(name, owner:)
|
15
|
+
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
16
|
+
owner, name, writer: true,
|
17
|
+
) do |temp_method_name, attr_name_expr|
|
18
|
+
owner <<
|
19
|
+
"def #{temp_method_name}(value)" <<
|
20
|
+
" _write_attribute(#{attr_name_expr}, value)" <<
|
21
|
+
"end"
|
22
|
+
end
|
29
23
|
end
|
30
24
|
end
|
31
25
|
|
@@ -33,35 +27,25 @@ module ActiveRecord
|
|
33
27
|
# specified +value+. Empty strings for Integer and Float columns are
|
34
28
|
# turned into +nil+.
|
35
29
|
def write_attribute(attr_name, value)
|
36
|
-
name =
|
37
|
-
|
38
|
-
else
|
39
|
-
attr_name.to_s
|
40
|
-
end
|
30
|
+
name = attr_name.to_s
|
31
|
+
name = self.class.attribute_aliases[name] || name
|
41
32
|
|
42
|
-
|
43
|
-
name
|
44
|
-
sync_with_transaction_state if name == primary_key
|
45
|
-
_write_attribute(name, value)
|
33
|
+
name = @primary_key if name == "id" && @primary_key
|
34
|
+
@attributes.write_from_user(name, value)
|
46
35
|
end
|
47
36
|
|
48
37
|
# This method exists to avoid the expensive primary_key check internally, without
|
49
38
|
# breaking compatibility with the write_attribute API
|
50
39
|
def _write_attribute(attr_name, value) # :nodoc:
|
51
|
-
@attributes.write_from_user(attr_name
|
52
|
-
value
|
40
|
+
@attributes.write_from_user(attr_name, value)
|
53
41
|
end
|
54
42
|
|
43
|
+
alias :attribute= :_write_attribute
|
44
|
+
private :attribute=
|
45
|
+
|
55
46
|
private
|
56
47
|
def write_attribute_without_type_cast(attr_name, value)
|
57
|
-
|
58
|
-
@attributes.write_cast_value(name, value)
|
59
|
-
value
|
60
|
-
end
|
61
|
-
|
62
|
-
# Handle *= for method_missing.
|
63
|
-
def attribute=(attribute_name, value)
|
64
|
-
_write_attribute(attribute_name, value)
|
48
|
+
@attributes.write_cast_value(attr_name, value)
|
65
49
|
end
|
66
50
|
end
|
67
51
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "mutex_m"
|
4
|
+
require "active_support/core_ext/enumerable"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
# = Active Record Attribute Methods
|
@@ -18,25 +19,25 @@ module ActiveRecord
|
|
18
19
|
include TimeZoneConversion
|
19
20
|
include Dirty
|
20
21
|
include Serialization
|
21
|
-
|
22
|
-
delegate :column_for_attribute, to: :class
|
23
22
|
end
|
24
23
|
|
25
|
-
|
26
|
-
def self.set_name_cache(name, value)
|
27
|
-
const_name = "ATTR_#{name}"
|
28
|
-
unless const_defined? const_name
|
29
|
-
const_set const_name, value.dup.freeze
|
30
|
-
end
|
31
|
-
end
|
32
|
-
}
|
33
|
-
|
34
|
-
BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
24
|
+
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
35
25
|
|
36
26
|
class GeneratedAttributeMethods < Module #:nodoc:
|
37
27
|
include Mutex_m
|
38
28
|
end
|
39
29
|
|
30
|
+
class << self
|
31
|
+
def dangerous_attribute_methods # :nodoc:
|
32
|
+
@dangerous_attribute_methods ||= (
|
33
|
+
Base.instance_methods +
|
34
|
+
Base.private_instance_methods -
|
35
|
+
Base.superclass.instance_methods -
|
36
|
+
Base.superclass.private_instance_methods
|
37
|
+
).map { |m| -m.to_s }.to_set.freeze
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
40
41
|
module ClassMethods
|
41
42
|
def inherited(child_class) #:nodoc:
|
42
43
|
child_class.initialize_generated_modules
|
@@ -44,7 +45,8 @@ module ActiveRecord
|
|
44
45
|
end
|
45
46
|
|
46
47
|
def initialize_generated_modules # :nodoc:
|
47
|
-
@generated_attribute_methods = GeneratedAttributeMethods.new
|
48
|
+
@generated_attribute_methods = const_set(:GeneratedAttributeMethods, GeneratedAttributeMethods.new)
|
49
|
+
private_constant :GeneratedAttributeMethods
|
48
50
|
@attribute_methods_generated = false
|
49
51
|
include @generated_attribute_methods
|
50
52
|
|
@@ -59,7 +61,7 @@ module ActiveRecord
|
|
59
61
|
# attribute methods.
|
60
62
|
generated_attribute_methods.synchronize do
|
61
63
|
return false if @attribute_methods_generated
|
62
|
-
superclass.define_attribute_methods unless
|
64
|
+
superclass.define_attribute_methods unless base_class?
|
63
65
|
super(attribute_names)
|
64
66
|
@attribute_methods_generated = true
|
65
67
|
end
|
@@ -105,7 +107,7 @@ module ActiveRecord
|
|
105
107
|
# A method name is 'dangerous' if it is already (re)defined by Active Record, but
|
106
108
|
# not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
|
107
109
|
def dangerous_attribute_method?(name) # :nodoc:
|
108
|
-
|
110
|
+
::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(name.to_s)
|
109
111
|
end
|
110
112
|
|
111
113
|
def method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
|
@@ -123,13 +125,11 @@ module ActiveRecord
|
|
123
125
|
# A class method is 'dangerous' if it is already (re)defined by Active Record, but
|
124
126
|
# not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
|
125
127
|
def dangerous_class_method?(method_name)
|
126
|
-
|
127
|
-
end
|
128
|
+
return true if RESTRICTED_CLASS_METHODS.include?(method_name.to_s)
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
klass.method(name).owner != superklass.method(name).owner
|
130
|
+
if Base.respond_to?(method_name, true)
|
131
|
+
if Object.respond_to?(method_name, true)
|
132
|
+
Base.method(method_name).owner != Object.method(method_name).owner
|
133
133
|
else
|
134
134
|
true
|
135
135
|
end
|
@@ -148,7 +148,7 @@ module ActiveRecord
|
|
148
148
|
# Person.attribute_method?(:age=) # => true
|
149
149
|
# Person.attribute_method?(:nothing) # => false
|
150
150
|
def attribute_method?(attribute)
|
151
|
-
super || (table_exists? && column_names.include?(attribute.to_s.
|
151
|
+
super || (table_exists? && column_names.include?(attribute.to_s.delete_suffix("=")))
|
152
152
|
end
|
153
153
|
|
154
154
|
# Returns an array of column names as strings if it's not an abstract class and
|
@@ -164,90 +164,27 @@ module ActiveRecord
|
|
164
164
|
attribute_types.keys
|
165
165
|
else
|
166
166
|
[]
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
# Regexp whitelist. Matches the following:
|
171
|
-
# "#{table_name}.#{column_name}"
|
172
|
-
# "#{column_name}"
|
173
|
-
COLUMN_NAME_WHITELIST = /\A(?:\w+\.)?\w+\z/i
|
174
|
-
|
175
|
-
# Regexp whitelist. Matches the following:
|
176
|
-
# "#{table_name}.#{column_name}"
|
177
|
-
# "#{table_name}.#{column_name} #{direction}"
|
178
|
-
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
|
179
|
-
# "#{table_name}.#{column_name} NULLS LAST"
|
180
|
-
# "#{column_name}"
|
181
|
-
# "#{column_name} #{direction}"
|
182
|
-
# "#{column_name} #{direction} NULLS FIRST"
|
183
|
-
# "#{column_name} NULLS LAST"
|
184
|
-
COLUMN_NAME_ORDER_WHITELIST = /
|
185
|
-
\A
|
186
|
-
(?:\w+\.)?
|
187
|
-
\w+
|
188
|
-
(?:\s+asc|\s+desc)?
|
189
|
-
(?:\s+nulls\s+(?:first|last))?
|
190
|
-
\z
|
191
|
-
/ix
|
192
|
-
|
193
|
-
def enforce_raw_sql_whitelist(args, whitelist: COLUMN_NAME_WHITELIST) # :nodoc:
|
194
|
-
unexpected = args.reject do |arg|
|
195
|
-
arg.kind_of?(Arel::Node) ||
|
196
|
-
arg.is_a?(Arel::Nodes::SqlLiteral) ||
|
197
|
-
arg.is_a?(Arel::Attributes::Attribute) ||
|
198
|
-
arg.to_s.split(/\s*,\s*/).all? { |part| whitelist.match?(part) }
|
199
|
-
end
|
200
|
-
|
201
|
-
return if unexpected.none?
|
202
|
-
|
203
|
-
if allow_unsafe_raw_sql == :deprecated
|
204
|
-
ActiveSupport::Deprecation.warn(
|
205
|
-
"Dangerous query method (method whose arguments are used as raw " \
|
206
|
-
"SQL) called with non-attribute argument(s): " \
|
207
|
-
"#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
|
208
|
-
"arguments will be disallowed in Rails 6.0. This method should " \
|
209
|
-
"not be called with user-provided values, such as request " \
|
210
|
-
"parameters or model attributes. Known-safe values can be passed " \
|
211
|
-
"by wrapping them in Arel.sql()."
|
212
|
-
)
|
213
|
-
else
|
214
|
-
raise(ActiveRecord::UnknownAttributeReference,
|
215
|
-
"Query method called with non-attribute argument(s): " +
|
216
|
-
unexpected.map(&:inspect).join(", ")
|
217
|
-
)
|
218
|
-
end
|
167
|
+
end.freeze
|
219
168
|
end
|
220
169
|
|
221
170
|
# Returns true if the given attribute exists, otherwise false.
|
222
171
|
#
|
223
172
|
# class Person < ActiveRecord::Base
|
173
|
+
# alias_attribute :new_name, :name
|
224
174
|
# end
|
225
175
|
#
|
226
|
-
# Person.has_attribute?('name')
|
227
|
-
# Person.has_attribute?(
|
228
|
-
# Person.has_attribute?(:
|
176
|
+
# Person.has_attribute?('name') # => true
|
177
|
+
# Person.has_attribute?('new_name') # => true
|
178
|
+
# Person.has_attribute?(:age) # => true
|
179
|
+
# Person.has_attribute?(:nothing) # => false
|
229
180
|
def has_attribute?(attr_name)
|
230
|
-
|
181
|
+
attr_name = attr_name.to_s
|
182
|
+
attr_name = attribute_aliases[attr_name] || attr_name
|
183
|
+
attribute_types.key?(attr_name)
|
231
184
|
end
|
232
185
|
|
233
|
-
|
234
|
-
|
235
|
-
# named attribute does not exist.
|
236
|
-
#
|
237
|
-
# class Person < ActiveRecord::Base
|
238
|
-
# end
|
239
|
-
#
|
240
|
-
# person = Person.new
|
241
|
-
# person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
|
242
|
-
# # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
|
243
|
-
#
|
244
|
-
# person.column_for_attribute(:nothing)
|
245
|
-
# # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
|
246
|
-
def column_for_attribute(name)
|
247
|
-
name = name.to_s
|
248
|
-
columns_hash.fetch(name) do
|
249
|
-
ConnectionAdapters::NullColumn.new(name)
|
250
|
-
end
|
186
|
+
def _has_attribute?(attr_name) # :nodoc:
|
187
|
+
attribute_types.key?(attr_name)
|
251
188
|
end
|
252
189
|
end
|
253
190
|
|
@@ -270,21 +207,14 @@ module ActiveRecord
|
|
270
207
|
def respond_to?(name, include_private = false)
|
271
208
|
return false unless super
|
272
209
|
|
273
|
-
case name
|
274
|
-
when :to_partial_path
|
275
|
-
name = "to_partial_path".freeze
|
276
|
-
when :to_model
|
277
|
-
name = "to_model".freeze
|
278
|
-
else
|
279
|
-
name = name.to_s
|
280
|
-
end
|
281
|
-
|
282
210
|
# If the result is true then check for the select case.
|
283
211
|
# For queries selecting a subset of columns, return false for unselected columns.
|
284
212
|
# We check defined?(@attributes) not to issue warnings if called on objects that
|
285
213
|
# have been allocated but not yet initialized.
|
286
|
-
if defined?(@attributes)
|
287
|
-
|
214
|
+
if defined?(@attributes)
|
215
|
+
if name = self.class.symbol_column_to_string(name.to_sym)
|
216
|
+
return _has_attribute?(name)
|
217
|
+
end
|
288
218
|
end
|
289
219
|
|
290
220
|
true
|
@@ -293,14 +223,22 @@ module ActiveRecord
|
|
293
223
|
# Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
|
294
224
|
#
|
295
225
|
# class Person < ActiveRecord::Base
|
226
|
+
# alias_attribute :new_name, :name
|
296
227
|
# end
|
297
228
|
#
|
298
229
|
# person = Person.new
|
299
|
-
# person.has_attribute?(:name)
|
300
|
-
# person.has_attribute?(
|
301
|
-
# person.has_attribute?(
|
230
|
+
# person.has_attribute?(:name) # => true
|
231
|
+
# person.has_attribute?(:new_name) # => true
|
232
|
+
# person.has_attribute?('age') # => true
|
233
|
+
# person.has_attribute?(:nothing) # => false
|
302
234
|
def has_attribute?(attr_name)
|
303
|
-
|
235
|
+
attr_name = attr_name.to_s
|
236
|
+
attr_name = self.class.attribute_aliases[attr_name] || attr_name
|
237
|
+
@attributes.key?(attr_name)
|
238
|
+
end
|
239
|
+
|
240
|
+
def _has_attribute?(attr_name) # :nodoc:
|
241
|
+
@attributes.key?(attr_name)
|
304
242
|
end
|
305
243
|
|
306
244
|
# Returns an array of names for the attributes available on this object.
|
@@ -344,15 +282,10 @@ module ActiveRecord
|
|
344
282
|
# person.attribute_for_inspect(:tag_ids)
|
345
283
|
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
|
346
284
|
def attribute_for_inspect(attr_name)
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
elsif value.is_a?(Date) || value.is_a?(Time)
|
352
|
-
%("#{value.to_s(:db)}")
|
353
|
-
else
|
354
|
-
value.inspect
|
355
|
-
end
|
285
|
+
attr_name = attr_name.to_s
|
286
|
+
attr_name = self.class.attribute_aliases[attr_name] || attr_name
|
287
|
+
value = _read_attribute(attr_name)
|
288
|
+
format_for_inspect(attr_name, value)
|
356
289
|
end
|
357
290
|
|
358
291
|
# Returns +true+ if the specified +attribute+ has been set by the user or by a
|
@@ -370,8 +303,10 @@ module ActiveRecord
|
|
370
303
|
# task.is_done = true
|
371
304
|
# task.attribute_present?(:title) # => true
|
372
305
|
# task.attribute_present?(:is_done) # => true
|
373
|
-
def attribute_present?(
|
374
|
-
|
306
|
+
def attribute_present?(attr_name)
|
307
|
+
attr_name = attr_name.to_s
|
308
|
+
attr_name = self.class.attribute_aliases[attr_name] || attr_name
|
309
|
+
value = _read_attribute(attr_name)
|
375
310
|
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
|
376
311
|
end
|
377
312
|
|
@@ -443,50 +378,53 @@ module ActiveRecord
|
|
443
378
|
@attributes.accessed
|
444
379
|
end
|
445
380
|
|
446
|
-
|
447
|
-
|
448
|
-
def attribute_method?(attr_name) # :nodoc:
|
381
|
+
private
|
382
|
+
def attribute_method?(attr_name)
|
449
383
|
# We check defined? because Syck calls respond_to? before actually calling initialize.
|
450
384
|
defined?(@attributes) && @attributes.key?(attr_name)
|
451
385
|
end
|
452
386
|
|
453
|
-
private
|
454
|
-
|
455
|
-
def attributes_with_values_for_create(attribute_names)
|
456
|
-
attributes_with_values(attributes_for_create(attribute_names))
|
457
|
-
end
|
458
|
-
|
459
|
-
def attributes_with_values_for_update(attribute_names)
|
460
|
-
attributes_with_values(attributes_for_update(attribute_names))
|
461
|
-
end
|
462
|
-
|
463
387
|
def attributes_with_values(attribute_names)
|
464
|
-
attribute_names.
|
465
|
-
|
388
|
+
attribute_names.index_with do |name|
|
389
|
+
_read_attribute(name)
|
466
390
|
end
|
467
391
|
end
|
468
392
|
|
469
393
|
# Filters the primary keys and readonly attributes from the attribute names.
|
470
394
|
def attributes_for_update(attribute_names)
|
471
|
-
attribute_names
|
472
|
-
|
395
|
+
attribute_names &= self.class.column_names
|
396
|
+
attribute_names.delete_if do |name|
|
397
|
+
self.class.readonly_attribute?(name)
|
473
398
|
end
|
474
399
|
end
|
475
400
|
|
476
401
|
# Filters out the primary keys, from the attribute names, when the primary
|
477
402
|
# key is to be generated (e.g. the id attribute has no value).
|
478
403
|
def attributes_for_create(attribute_names)
|
479
|
-
attribute_names
|
404
|
+
attribute_names &= self.class.column_names
|
405
|
+
attribute_names.delete_if do |name|
|
480
406
|
pk_attribute?(name) && id.nil?
|
481
407
|
end
|
482
408
|
end
|
483
409
|
|
484
|
-
def
|
485
|
-
|
410
|
+
def format_for_inspect(name, value)
|
411
|
+
if value.nil?
|
412
|
+
value.inspect
|
413
|
+
else
|
414
|
+
inspected_value = if value.is_a?(String) && value.length > 50
|
415
|
+
"#{value[0, 50]}...".inspect
|
416
|
+
elsif value.is_a?(Date) || value.is_a?(Time)
|
417
|
+
%("#{value.to_s(:inspect)}")
|
418
|
+
else
|
419
|
+
value.inspect
|
420
|
+
end
|
421
|
+
|
422
|
+
inspection_filter.filter_param(name, inspected_value)
|
423
|
+
end
|
486
424
|
end
|
487
425
|
|
488
426
|
def pk_attribute?(name)
|
489
|
-
name ==
|
427
|
+
name == @primary_key
|
490
428
|
end
|
491
429
|
end
|
492
430
|
end
|
@@ -12,6 +12,9 @@ module ActiveRecord
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ClassMethods
|
15
|
+
##
|
16
|
+
# :call-seq: attribute(name, cast_type = nil, **options)
|
17
|
+
#
|
15
18
|
# Defines an attribute with a type on this model. It will override the
|
16
19
|
# type of existing attributes if needed. This allows control over how
|
17
20
|
# values are converted to and from SQL when assigned to a model. It also
|
@@ -41,6 +44,9 @@ module ActiveRecord
|
|
41
44
|
# +range+ (PostgreSQL only) specifies that the type should be a range (see the
|
42
45
|
# examples below).
|
43
46
|
#
|
47
|
+
# When using a symbol for +cast_type+, extra options are forwarded to the
|
48
|
+
# constructor of the type object.
|
49
|
+
#
|
44
50
|
# ==== Examples
|
45
51
|
#
|
46
52
|
# The type detected by Active Record can be overridden.
|
@@ -112,6 +118,16 @@ module ActiveRecord
|
|
112
118
|
# my_float_range: 1.0..3.5
|
113
119
|
# }
|
114
120
|
#
|
121
|
+
# Passing options to the type constructor
|
122
|
+
#
|
123
|
+
# # app/models/my_model.rb
|
124
|
+
# class MyModel < ActiveRecord::Base
|
125
|
+
# attribute :small_int, :integer, limit: 2
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# MyModel.create(small_int: 65537)
|
129
|
+
# # => Error: 65537 is out of range for the limit of two bytes
|
130
|
+
#
|
115
131
|
# ==== Creating Custom Types
|
116
132
|
#
|
117
133
|
# Users may also define their own custom types, as long as they respond
|
@@ -157,7 +173,7 @@ module ActiveRecord
|
|
157
173
|
# class Money < Struct.new(:amount, :currency)
|
158
174
|
# end
|
159
175
|
#
|
160
|
-
# class MoneyType < Type::Value
|
176
|
+
# class MoneyType < ActiveRecord::Type::Value
|
161
177
|
# def initialize(currency_converter:)
|
162
178
|
# @currency_converter = currency_converter
|
163
179
|
# end
|
@@ -192,13 +208,13 @@ module ActiveRecord
|
|
192
208
|
# tracking is performed. The methods +changed?+ and +changed_in_place?+
|
193
209
|
# will be called from ActiveModel::Dirty. See the documentation for those
|
194
210
|
# methods in ActiveModel::Type::Value for more details.
|
195
|
-
def attribute(name, cast_type =
|
211
|
+
def attribute(name, cast_type = nil, **options, &block)
|
196
212
|
name = name.to_s
|
197
213
|
reload_schema_from_cache
|
198
214
|
|
199
215
|
self.attributes_to_define_after_schema_loads =
|
200
216
|
attributes_to_define_after_schema_loads.merge(
|
201
|
-
name => [cast_type, options]
|
217
|
+
name => [cast_type || block, options]
|
202
218
|
)
|
203
219
|
end
|
204
220
|
|
@@ -233,16 +249,11 @@ module ActiveRecord
|
|
233
249
|
def load_schema! # :nodoc:
|
234
250
|
super
|
235
251
|
attributes_to_define_after_schema_loads.each do |name, (type, options)|
|
236
|
-
|
237
|
-
type = ActiveRecord::Type.lookup(type, **options.except(:default))
|
238
|
-
end
|
239
|
-
|
240
|
-
define_attribute(name, type, **options.slice(:default))
|
252
|
+
define_attribute(name, _lookup_cast_type(name, type, options), **options.slice(:default))
|
241
253
|
end
|
242
254
|
end
|
243
255
|
|
244
256
|
private
|
245
|
-
|
246
257
|
NO_DEFAULT_PROVIDED = Object.new # :nodoc:
|
247
258
|
private_constant :NO_DEFAULT_PROVIDED
|
248
259
|
|
@@ -261,6 +272,32 @@ module ActiveRecord
|
|
261
272
|
end
|
262
273
|
_default_attributes[name] = default_attribute
|
263
274
|
end
|
275
|
+
|
276
|
+
def decorate_attribute_type(attr_name, **default)
|
277
|
+
type, options = attributes_to_define_after_schema_loads[attr_name]
|
278
|
+
|
279
|
+
default.with_defaults!(default: options[:default]) if options&.key?(:default)
|
280
|
+
|
281
|
+
attribute(attr_name, **default) do |cast_type|
|
282
|
+
if type && !type.is_a?(Proc)
|
283
|
+
cast_type = _lookup_cast_type(attr_name, type, options)
|
284
|
+
end
|
285
|
+
|
286
|
+
yield cast_type
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def _lookup_cast_type(name, type, options)
|
291
|
+
case type
|
292
|
+
when Symbol
|
293
|
+
adapter_name = ActiveRecord::Type.adapter_name_from(self)
|
294
|
+
ActiveRecord::Type.lookup(type, **options.except(:default), adapter: adapter_name)
|
295
|
+
when Proc
|
296
|
+
type[type_for_attribute(name)]
|
297
|
+
else
|
298
|
+
type || type_for_attribute(name)
|
299
|
+
end
|
300
|
+
end
|
264
301
|
end
|
265
302
|
end
|
266
303
|
end
|