activerecord 5.1.0 → 5.2.3
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 +596 -450
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations.rb +77 -85
- data/lib/active_record/associations/alias_tracker.rb +23 -32
- data/lib/active_record/associations/association.rb +49 -35
- data/lib/active_record/associations/association_scope.rb +55 -55
- data/lib/active_record/associations/belongs_to_association.rb +30 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +66 -53
- data/lib/active_record/associations/collection_proxy.rb +30 -73
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +13 -2
- data/lib/active_record/associations/has_many_through_association.rb +37 -19
- data/lib/active_record/associations/has_one_association.rb +14 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency.rb +52 -96
- data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/preloader.rb +17 -37
- data/lib/active_record/associations/preloader/association.rb +53 -92
- data/lib/active_record/associations/preloader/through_association.rb +72 -73
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +27 -12
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +33 -216
- data/lib/active_record/attribute_methods/primary_key.rb +10 -13
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +22 -19
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +15 -13
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +12 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
- data/lib/active_record/connection_adapters/column.rb +4 -2
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -23
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- 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 +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +258 -129
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -87
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +90 -96
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +41 -61
- data/lib/active_record/counter_cache.rb +20 -15
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +18 -13
- data/lib/active_record/errors.rb +60 -15
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +30 -42
- data/lib/active_record/locking/pessimistic.rb +10 -7
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +81 -29
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/model_schema.rb +74 -58
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +199 -54
- data/lib/active_record/query_cache.rb +8 -10
- data/lib/active_record/querying.rb +5 -3
- data/lib/active_record/railtie.rb +62 -6
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +48 -38
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +137 -207
- data/lib/active_record/relation.rb +132 -207
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/calculations.rb +66 -25
- data/lib/active_record/relation/delegation.rb +45 -29
- data/lib/active_record/relation/finder_methods.rb +76 -85
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +135 -103
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -67
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping.rb +12 -10
- data/lib/active_record/scoping/default.rb +10 -7
- data/lib/active_record/scoping/named.rb +40 -12
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +22 -12
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +38 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +32 -27
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +6 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +36 -6
- data/lib/active_record/version.rb +2 -0
- data/lib/rails/generators/active_record.rb +3 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +24 -36
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute_mutation_tracker.rb +0 -113
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/attribute_set/builder.rb +0 -124
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
class SingularAssociation < Association #:nodoc:
|
@@ -15,9 +17,8 @@ module ActiveRecord
|
|
15
17
|
replace(record)
|
16
18
|
end
|
17
19
|
|
18
|
-
def build(attributes = {})
|
19
|
-
record = build_record(attributes)
|
20
|
-
yield(record) if block_given?
|
20
|
+
def build(attributes = {}, &block)
|
21
|
+
record = build_record(attributes, &block)
|
21
22
|
set_new_record(record)
|
22
23
|
record
|
23
24
|
end
|
@@ -30,24 +31,22 @@ module ActiveRecord
|
|
30
31
|
end
|
31
32
|
|
32
33
|
private
|
33
|
-
|
34
|
-
|
35
|
-
scope.scope_for_create.stringify_keys.except(klass.primary_key)
|
34
|
+
def scope_for_create
|
35
|
+
super.except!(klass.primary_key)
|
36
36
|
end
|
37
37
|
|
38
38
|
def find_target
|
39
|
-
|
39
|
+
scope = self.scope
|
40
|
+
return scope.take if skip_statement_cache?(scope)
|
40
41
|
|
41
42
|
conn = klass.connection
|
42
|
-
sc = reflection.association_scope_cache(conn, owner) do
|
43
|
-
|
44
|
-
|
45
|
-
target_scope.merge(as.scope(self, conn)).limit(1)
|
46
|
-
}
|
43
|
+
sc = reflection.association_scope_cache(conn, owner) do |params|
|
44
|
+
as = AssociationScope.create { params.bind }
|
45
|
+
target_scope.merge!(as.scope(self)).limit(1)
|
47
46
|
end
|
48
47
|
|
49
48
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
50
|
-
sc.execute(binds,
|
49
|
+
sc.execute(binds, conn) do |record|
|
51
50
|
set_inverse_instance record
|
52
51
|
end.first
|
53
52
|
rescue ::RangeError
|
@@ -62,9 +61,8 @@ module ActiveRecord
|
|
62
61
|
replace(record)
|
63
62
|
end
|
64
63
|
|
65
|
-
def _create_record(attributes, raise_error = false)
|
66
|
-
record = build_record(attributes)
|
67
|
-
yield(record) if block_given?
|
64
|
+
def _create_record(attributes, raise_error = false, &block)
|
65
|
+
record = build_record(attributes, &block)
|
68
66
|
saved = record.save
|
69
67
|
set_new_record(record)
|
70
68
|
raise RecordInvalid.new(record) if !saved && raise_error
|
@@ -1,10 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Through Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Through Association
|
4
6
|
module ThroughAssociation #:nodoc:
|
5
|
-
delegate :source_reflection,
|
7
|
+
delegate :source_reflection, to: :reflection
|
6
8
|
|
7
9
|
private
|
10
|
+
def through_reflection
|
11
|
+
@through_reflection ||= begin
|
12
|
+
refl = reflection.through_reflection
|
13
|
+
|
14
|
+
while refl.through_reflection?
|
15
|
+
refl = refl.through_reflection
|
16
|
+
end
|
17
|
+
|
18
|
+
refl
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def through_association
|
23
|
+
@through_association ||= owner.association(through_reflection.name)
|
24
|
+
end
|
8
25
|
|
9
26
|
# We merge in these scopes for two reasons:
|
10
27
|
#
|
@@ -13,7 +30,7 @@ module ActiveRecord
|
|
13
30
|
def target_scope
|
14
31
|
scope = super
|
15
32
|
reflection.chain.drop(1).each do |reflection|
|
16
|
-
relation = reflection.klass.
|
33
|
+
relation = reflection.klass.scope_for_association
|
17
34
|
scope.merge!(
|
18
35
|
relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
|
19
36
|
)
|
@@ -36,24 +53,22 @@ module ActiveRecord
|
|
36
53
|
def construct_join_attributes(*records)
|
37
54
|
ensure_mutable
|
38
55
|
|
39
|
-
|
56
|
+
association_primary_key = source_reflection.association_primary_key(reflection.klass)
|
57
|
+
|
58
|
+
if association_primary_key == reflection.klass.primary_key && !options[:source_type]
|
40
59
|
join_attributes = { source_reflection.name => records }
|
41
60
|
else
|
42
61
|
join_attributes = {
|
43
|
-
source_reflection.foreign_key =>
|
44
|
-
records.map { |record|
|
45
|
-
record.send(source_reflection.association_primary_key(reflection.klass))
|
46
|
-
}
|
62
|
+
source_reflection.foreign_key => records.map(&association_primary_key.to_sym)
|
47
63
|
}
|
48
64
|
end
|
49
65
|
|
50
66
|
if options[:source_type]
|
51
|
-
join_attributes[source_reflection.foreign_type] =
|
52
|
-
records.map { |record| record.class.base_class.name }
|
67
|
+
join_attributes[source_reflection.foreign_type] = [ options[:source_type] ]
|
53
68
|
end
|
54
69
|
|
55
70
|
if records.count == 1
|
56
|
-
|
71
|
+
join_attributes.transform_values!(&:first)
|
57
72
|
else
|
58
73
|
join_attributes
|
59
74
|
end
|
@@ -99,7 +114,7 @@ module ActiveRecord
|
|
99
114
|
attributes[inverse.foreign_key] = target.id
|
100
115
|
end
|
101
116
|
|
102
|
-
super
|
117
|
+
super
|
103
118
|
end
|
104
119
|
end
|
105
120
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_model/forbidden_attributes_protection"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -5,11 +7,6 @@ module ActiveRecord
|
|
5
7
|
extend ActiveSupport::Concern
|
6
8
|
include ActiveModel::AttributeAssignment
|
7
9
|
|
8
|
-
# Alias for ActiveModel::AttributeAssignment#assign_attributes. See ActiveModel::AttributeAssignment.
|
9
|
-
def attributes=(attributes)
|
10
|
-
assign_attributes(attributes)
|
11
|
-
end
|
12
|
-
|
13
10
|
private
|
14
11
|
|
15
12
|
def _assign_attributes(attributes)
|
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module AttributeDecorators # :nodoc:
|
3
5
|
extend ActiveSupport::Concern
|
4
6
|
|
5
7
|
included do
|
6
|
-
class_attribute :attribute_type_decorations, instance_accessor: false # :internal:
|
7
|
-
self.attribute_type_decorations = TypeDecorator.new
|
8
|
+
class_attribute :attribute_type_decorations, instance_accessor: false, default: TypeDecorator.new # :internal:
|
8
9
|
end
|
9
10
|
|
10
11
|
module ClassMethods # :nodoc:
|
@@ -1,7 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
require "mutex_m"
|
4
|
-
require "concurrent/map"
|
5
4
|
|
6
5
|
module ActiveRecord
|
7
6
|
# = Active Record Attribute Methods
|
@@ -34,7 +33,9 @@ module ActiveRecord
|
|
34
33
|
|
35
34
|
BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
36
35
|
|
37
|
-
class GeneratedAttributeMethods < Module
|
36
|
+
class GeneratedAttributeMethods < Module #:nodoc:
|
37
|
+
include Mutex_m
|
38
|
+
end
|
38
39
|
|
39
40
|
module ClassMethods
|
40
41
|
def inherited(child_class) #:nodoc:
|
@@ -43,7 +44,7 @@ module ActiveRecord
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def initialize_generated_modules # :nodoc:
|
46
|
-
@generated_attribute_methods = GeneratedAttributeMethods.new
|
47
|
+
@generated_attribute_methods = GeneratedAttributeMethods.new
|
47
48
|
@attribute_methods_generated = false
|
48
49
|
include @generated_attribute_methods
|
49
50
|
|
@@ -62,7 +63,6 @@ module ActiveRecord
|
|
62
63
|
super(attribute_names)
|
63
64
|
@attribute_methods_generated = true
|
64
65
|
end
|
65
|
-
true
|
66
66
|
end
|
67
67
|
|
68
68
|
def undefine_attribute_methods # :nodoc:
|
@@ -167,6 +167,57 @@ module ActiveRecord
|
|
167
167
|
end
|
168
168
|
end
|
169
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
|
219
|
+
end
|
220
|
+
|
170
221
|
# Returns true if the given attribute exists, otherwise false.
|
171
222
|
#
|
172
223
|
# class Person < ActiveRecord::Base
|
@@ -236,7 +287,7 @@ module ActiveRecord
|
|
236
287
|
return has_attribute?(name)
|
237
288
|
end
|
238
289
|
|
239
|
-
|
290
|
+
true
|
240
291
|
end
|
241
292
|
|
242
293
|
# Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
|
@@ -401,24 +452,18 @@ module ActiveRecord
|
|
401
452
|
|
402
453
|
private
|
403
454
|
|
404
|
-
def
|
405
|
-
|
455
|
+
def attributes_with_values_for_create(attribute_names)
|
456
|
+
attributes_with_values(attributes_for_create(attribute_names))
|
406
457
|
end
|
407
458
|
|
408
|
-
def
|
409
|
-
|
459
|
+
def attributes_with_values_for_update(attribute_names)
|
460
|
+
attributes_with_values(attributes_for_update(attribute_names))
|
410
461
|
end
|
411
462
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
attrs = {}
|
416
|
-
arel_table = self.class.arel_table
|
417
|
-
|
418
|
-
attribute_names.each do |name|
|
419
|
-
attrs[arel_table[name]] = typecasted_attribute_value(name)
|
463
|
+
def attributes_with_values(attribute_names)
|
464
|
+
attribute_names.each_with_object({}) do |name, attrs|
|
465
|
+
attrs[name] = _read_attribute(name)
|
420
466
|
end
|
421
|
-
attrs
|
422
467
|
end
|
423
468
|
|
424
469
|
# Filters the primary keys and readonly attributes from the attribute names.
|
@@ -443,9 +488,5 @@ module ActiveRecord
|
|
443
488
|
def pk_attribute?(name)
|
444
489
|
name == self.class.primary_key
|
445
490
|
end
|
446
|
-
|
447
|
-
def typecasted_attribute_value(name)
|
448
|
-
_read_attribute(name)
|
449
|
-
end
|
450
491
|
end
|
451
492
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "active_support/core_ext/module/attribute_accessors"
|
3
|
-
require "active_record/attribute_mutation_tracker"
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module AttributeMethods
|
7
|
-
module Dirty
|
7
|
+
module Dirty
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
10
|
include ActiveModel::Dirty
|
@@ -14,11 +14,7 @@ module ActiveRecord
|
|
14
14
|
raise "You cannot include Dirty after Timestamp"
|
15
15
|
end
|
16
16
|
|
17
|
-
class_attribute :partial_writes, instance_writer: false
|
18
|
-
self.partial_writes = true
|
19
|
-
|
20
|
-
after_create { changes_internally_applied }
|
21
|
-
after_update { changes_internally_applied }
|
17
|
+
class_attribute :partial_writes, instance_writer: false, default: true
|
22
18
|
|
23
19
|
# Attribute methods for "changed in last call to save?"
|
24
20
|
attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
|
@@ -30,106 +26,18 @@ module ActiveRecord
|
|
30
26
|
attribute_method_suffix("_change_to_be_saved", "_in_database")
|
31
27
|
end
|
32
28
|
|
33
|
-
# Attempts to +save+ the record and clears changed attributes if successful.
|
34
|
-
def save(*)
|
35
|
-
if status = super
|
36
|
-
changes_applied
|
37
|
-
end
|
38
|
-
status
|
39
|
-
end
|
40
|
-
|
41
|
-
# Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
|
42
|
-
def save!(*)
|
43
|
-
super.tap do
|
44
|
-
changes_applied
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
29
|
# <tt>reload</tt> the record and clears changed attributes.
|
49
30
|
def reload(*)
|
50
31
|
super.tap do
|
51
|
-
@
|
52
|
-
|
53
|
-
@
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
def initialize_dup(other) # :nodoc:
|
58
|
-
super
|
59
|
-
@attributes = self.class._default_attributes.map do |attr|
|
60
|
-
attr.with_value_from_user(@attributes.fetch_value(attr.name))
|
61
|
-
end
|
62
|
-
clear_mutation_trackers
|
63
|
-
end
|
64
|
-
|
65
|
-
def changes_internally_applied # :nodoc:
|
66
|
-
@mutations_before_last_save = mutation_tracker
|
67
|
-
forget_attribute_assignments
|
68
|
-
@mutations_from_database = AttributeMutationTracker.new(@attributes)
|
69
|
-
end
|
70
|
-
|
71
|
-
def changes_applied
|
72
|
-
@previous_mutation_tracker = mutation_tracker
|
73
|
-
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
|
74
|
-
clear_mutation_trackers
|
75
|
-
end
|
76
|
-
|
77
|
-
def clear_changes_information
|
78
|
-
@previous_mutation_tracker = nil
|
79
|
-
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
|
80
|
-
forget_attribute_assignments
|
81
|
-
clear_mutation_trackers
|
82
|
-
end
|
83
|
-
|
84
|
-
def raw_write_attribute(attr_name, *)
|
85
|
-
result = super
|
86
|
-
clear_attribute_change(attr_name)
|
87
|
-
result
|
88
|
-
end
|
89
|
-
|
90
|
-
def clear_attribute_changes(attr_names)
|
91
|
-
super
|
92
|
-
attr_names.each do |attr_name|
|
93
|
-
clear_attribute_change(attr_name)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def changed_attributes
|
98
|
-
# This should only be set by methods which will call changed_attributes
|
99
|
-
# multiple times when it is known that the computed value cannot change.
|
100
|
-
if defined?(@cached_changed_attributes)
|
101
|
-
@cached_changed_attributes
|
102
|
-
else
|
103
|
-
emit_warning_if_needed("changed_attributes", "saved_changes.transform_values(&:first)")
|
104
|
-
super.reverse_merge(mutation_tracker.changed_values).freeze
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def changes
|
109
|
-
cache_changed_attributes do
|
110
|
-
emit_warning_if_needed("changes", "saved_changes")
|
111
|
-
super
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def previous_changes
|
116
|
-
unless previous_mutation_tracker.equal?(mutations_before_last_save)
|
117
|
-
ActiveSupport::Deprecation.warn(<<-EOW.strip_heredoc)
|
118
|
-
The behavior of `previous_changes` inside of after callbacks is
|
119
|
-
deprecated without replacement. In the next release of Rails,
|
120
|
-
this method inside of `after_save` will return the changes that
|
121
|
-
were just saved.
|
122
|
-
EOW
|
32
|
+
@previously_changed = ActiveSupport::HashWithIndifferentAccess.new
|
33
|
+
@mutations_before_last_save = nil
|
34
|
+
@attributes_changed_by_setter = ActiveSupport::HashWithIndifferentAccess.new
|
35
|
+
@mutations_from_database = nil
|
123
36
|
end
|
124
|
-
previous_mutation_tracker.changes
|
125
|
-
end
|
126
|
-
|
127
|
-
def attribute_changed_in_place?(attr_name)
|
128
|
-
mutation_tracker.changed_in_place?(attr_name)
|
129
37
|
end
|
130
38
|
|
131
39
|
# Did this attribute change when we last saved? This method can be invoked
|
132
|
-
# as
|
40
|
+
# as +saved_change_to_name?+ instead of <tt>saved_change_to_attribute?("name")</tt>.
|
133
41
|
# Behaves similarly to +attribute_changed?+. This method is useful in
|
134
42
|
# after callbacks to determine if the call to save changed a certain
|
135
43
|
# attribute.
|
@@ -152,8 +60,8 @@ module ActiveRecord
|
|
152
60
|
# Behaves similarly to +attribute_change+. This method is useful in after
|
153
61
|
# callbacks, to see the change in an attribute that just occurred
|
154
62
|
#
|
155
|
-
# This method can be invoked as
|
156
|
-
#
|
63
|
+
# This method can be invoked as +saved_change_to_name+ in instead of
|
64
|
+
# <tt>saved_change_to_attribute("name")</tt>
|
157
65
|
def saved_change_to_attribute(attr_name)
|
158
66
|
mutations_before_last_save.change_to_attribute(attr_name)
|
159
67
|
end
|
@@ -166,7 +74,7 @@ module ActiveRecord
|
|
166
74
|
mutations_before_last_save.original_value(attr_name)
|
167
75
|
end
|
168
76
|
|
169
|
-
# Did the last call to
|
77
|
+
# Did the last call to +save+ have any changes to change?
|
170
78
|
def saved_changes?
|
171
79
|
mutations_before_last_save.any_changes?
|
172
80
|
end
|
@@ -176,158 +84,67 @@ module ActiveRecord
|
|
176
84
|
mutations_before_last_save.changes
|
177
85
|
end
|
178
86
|
|
179
|
-
# Alias for
|
87
|
+
# Alias for +attribute_changed?+
|
180
88
|
def will_save_change_to_attribute?(attr_name, **options)
|
181
89
|
mutations_from_database.changed?(attr_name, **options)
|
182
90
|
end
|
183
91
|
|
184
|
-
# Alias for
|
92
|
+
# Alias for +attribute_change+
|
185
93
|
def attribute_change_to_be_saved(attr_name)
|
186
94
|
mutations_from_database.change_to_attribute(attr_name)
|
187
95
|
end
|
188
96
|
|
189
|
-
# Alias for
|
97
|
+
# Alias for +attribute_was+
|
190
98
|
def attribute_in_database(attr_name)
|
191
99
|
mutations_from_database.original_value(attr_name)
|
192
100
|
end
|
193
101
|
|
194
|
-
# Alias for
|
102
|
+
# Alias for +changed?+
|
195
103
|
def has_changes_to_save?
|
196
104
|
mutations_from_database.any_changes?
|
197
105
|
end
|
198
106
|
|
199
|
-
# Alias for
|
107
|
+
# Alias for +changes+
|
200
108
|
def changes_to_save
|
201
109
|
mutations_from_database.changes
|
202
110
|
end
|
203
111
|
|
204
|
-
# Alias for
|
112
|
+
# Alias for +changed+
|
205
113
|
def changed_attribute_names_to_save
|
206
|
-
|
114
|
+
mutations_from_database.changed_attribute_names
|
207
115
|
end
|
208
116
|
|
209
|
-
# Alias for
|
117
|
+
# Alias for +changed_attributes+
|
210
118
|
def attributes_in_database
|
211
|
-
|
212
|
-
end
|
213
|
-
|
214
|
-
def attribute_was(*)
|
215
|
-
emit_warning_if_needed("attribute_was", "attribute_before_last_save")
|
216
|
-
super
|
217
|
-
end
|
218
|
-
|
219
|
-
def attribute_change(*)
|
220
|
-
emit_warning_if_needed("attribute_change", "saved_change_to_attribute")
|
221
|
-
super
|
222
|
-
end
|
223
|
-
|
224
|
-
def attribute_changed?(*)
|
225
|
-
emit_warning_if_needed("attribute_changed?", "saved_change_to_attribute?")
|
226
|
-
super
|
227
|
-
end
|
228
|
-
|
229
|
-
def changed?(*)
|
230
|
-
emit_warning_if_needed("changed?", "saved_changes?")
|
231
|
-
super
|
232
|
-
end
|
233
|
-
|
234
|
-
def changed(*)
|
235
|
-
emit_warning_if_needed("changed", "saved_changes.keys")
|
236
|
-
super
|
119
|
+
mutations_from_database.changed_values
|
237
120
|
end
|
238
121
|
|
239
122
|
private
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
end
|
245
|
-
@mutation_tracker ||= AttributeMutationTracker.new(@attributes)
|
246
|
-
end
|
247
|
-
|
248
|
-
def emit_warning_if_needed(method_name, new_method_name)
|
249
|
-
unless mutation_tracker.equal?(mutations_from_database)
|
250
|
-
ActiveSupport::Deprecation.warn(<<-EOW.squish)
|
251
|
-
The behavior of `#{method_name}` inside of after callbacks will
|
252
|
-
be changing in the next version of Rails. The new return value will reflect the
|
253
|
-
behavior of calling the method after `save` returned (e.g. the opposite of what
|
254
|
-
it returns now). To maintain the current behavior, use `#{new_method_name}`
|
255
|
-
instead.
|
256
|
-
EOW
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
def mutations_from_database
|
261
|
-
unless defined?(@mutations_from_database)
|
262
|
-
@mutations_from_database = nil
|
263
|
-
end
|
264
|
-
@mutations_from_database ||= mutation_tracker
|
265
|
-
end
|
266
|
-
|
267
|
-
def changes_include?(attr_name)
|
268
|
-
super || mutation_tracker.changed?(attr_name)
|
269
|
-
end
|
270
|
-
|
271
|
-
def clear_attribute_change(attr_name)
|
272
|
-
mutation_tracker.forget_change(attr_name)
|
273
|
-
mutations_from_database.forget_change(attr_name)
|
274
|
-
end
|
275
|
-
|
276
|
-
def attribute_will_change!(attr_name)
|
277
|
-
super
|
278
|
-
if self.class.has_attribute?(attr_name)
|
279
|
-
mutations_from_database.force_change(attr_name)
|
280
|
-
else
|
281
|
-
ActiveSupport::Deprecation.warn(<<-EOW.squish)
|
282
|
-
#{attr_name} is not an attribute known to Active Record.
|
283
|
-
This behavior is deprecated and will be removed in the next
|
284
|
-
version of Rails. If you'd like #{attr_name} to be managed
|
285
|
-
by Active Record, add `attribute :#{attr_name} to your class.
|
286
|
-
EOW
|
287
|
-
mutations_from_database.deprecated_force_change(attr_name)
|
123
|
+
def write_attribute_without_type_cast(attr_name, value)
|
124
|
+
name = attr_name.to_s
|
125
|
+
if self.class.attribute_alias?(name)
|
126
|
+
name = self.class.attribute_alias(name)
|
288
127
|
end
|
128
|
+
result = super(name, value)
|
129
|
+
clear_attribute_change(name)
|
130
|
+
result
|
289
131
|
end
|
290
132
|
|
291
133
|
def _update_record(*)
|
292
|
-
partial_writes? ? super(keys_for_partial_write) : super
|
134
|
+
affected_rows = partial_writes? ? super(keys_for_partial_write) : super
|
135
|
+
changes_applied
|
136
|
+
affected_rows
|
293
137
|
end
|
294
138
|
|
295
139
|
def _create_record(*)
|
296
|
-
partial_writes? ? super(keys_for_partial_write) : super
|
140
|
+
id = partial_writes? ? super(keys_for_partial_write) : super
|
141
|
+
changes_applied
|
142
|
+
id
|
297
143
|
end
|
298
144
|
|
299
145
|
def keys_for_partial_write
|
300
146
|
changed_attribute_names_to_save & self.class.column_names
|
301
147
|
end
|
302
|
-
|
303
|
-
def forget_attribute_assignments
|
304
|
-
@attributes = @attributes.map(&:forgetting_assignment)
|
305
|
-
end
|
306
|
-
|
307
|
-
def clear_mutation_trackers
|
308
|
-
@mutation_tracker = nil
|
309
|
-
@mutations_from_database = nil
|
310
|
-
@mutations_before_last_save = nil
|
311
|
-
end
|
312
|
-
|
313
|
-
def previous_mutation_tracker
|
314
|
-
@previous_mutation_tracker ||= NullMutationTracker.instance
|
315
|
-
end
|
316
|
-
|
317
|
-
def mutations_before_last_save
|
318
|
-
@mutations_before_last_save ||= previous_mutation_tracker
|
319
|
-
end
|
320
|
-
|
321
|
-
def cache_changed_attributes
|
322
|
-
@cached_changed_attributes = changed_attributes
|
323
|
-
yield
|
324
|
-
ensure
|
325
|
-
clear_changed_attributes_cache
|
326
|
-
end
|
327
|
-
|
328
|
-
def clear_changed_attributes_cache
|
329
|
-
remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
|
330
|
-
end
|
331
148
|
end
|
332
149
|
end
|
333
150
|
end
|