activerecord 5.1.0 → 5.2.0.rc1
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 +410 -530
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +4 -2
- data/lib/active_record/associations/alias_tracker.rb +23 -32
- data/lib/active_record/associations/association.rb +20 -21
- data/lib/active_record/associations/association_scope.rb +49 -49
- data/lib/active_record/associations/belongs_to_association.rb +12 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -7
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +10 -6
- 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 +50 -41
- data/lib/active_record/associations/collection_proxy.rb +22 -39
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +4 -2
- data/lib/active_record/associations/has_many_through_association.rb +12 -18
- data/lib/active_record/associations/has_one_association.rb +5 -1
- data/lib/active_record/associations/has_one_through_association.rb +8 -7
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -64
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -9
- data/lib/active_record/associations/join_dependency.rb +27 -44
- 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/preloader.rb +17 -37
- data/lib/active_record/associations/singular_association.rb +14 -10
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +68 -76
- data/lib/active_record/attribute_assignment.rb +2 -0
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +24 -214
- 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 +8 -2
- 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/attribute_methods.rb +48 -12
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +8 -11
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +8 -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 +14 -10
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +175 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -24
- 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 +58 -3
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +165 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +45 -9
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +118 -180
- 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 +2 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -17
- 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/array.rb +2 -0
- 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_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 +4 -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/oid.rb +2 -1
- 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 +14 -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 +269 -126
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +64 -85
- 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 +18 -0
- 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 +71 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +92 -95
- 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 +39 -60
- data/lib/active_record/counter_cache.rb +3 -2
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +17 -13
- data/lib/active_record/errors.rb +42 -3
- 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 +9 -9
- 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 +8 -6
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +74 -22
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +181 -137
- data/lib/active_record/model_schema.rb +73 -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 +153 -18
- data/lib/active_record/query_cache.rb +17 -12
- data/lib/active_record/querying.rb +4 -2
- data/lib/active_record/railtie.rb +61 -3
- 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 +47 -37
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +131 -204
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/calculations.rb +58 -20
- data/lib/active_record/relation/delegation.rb +10 -29
- data/lib/active_record/relation/finder_methods.rb +74 -85
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +51 -20
- 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 +54 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +53 -78
- data/lib/active_record/relation/query_attribute.rb +9 -2
- data/lib/active_record/relation/query_methods.rb +101 -95
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -1
- 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/relation.rb +99 -202
- 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/default.rb +10 -7
- data/lib/active_record/scoping/named.rb +38 -12
- data/lib/active_record/scoping.rb +12 -10
- 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 +37 -25
- 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 +5 -5
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +9 -7
- data/lib/active_record/translation.rb +2 -0
- 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 +2 -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.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.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 +35 -5
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- 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/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/migration.rb +2 -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
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +25 -37
- 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/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.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/attribute_set.rb +0 -113
- 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,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,10 @@ 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
|
17
|
+
class_attribute :partial_writes, instance_writer: false, default: true
|
19
18
|
|
20
|
-
after_create {
|
21
|
-
after_update {
|
19
|
+
after_create { changes_applied }
|
20
|
+
after_update { changes_applied }
|
22
21
|
|
23
22
|
# Attribute methods for "changed in last call to save?"
|
24
23
|
attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
|
@@ -30,106 +29,16 @@ module ActiveRecord
|
|
30
29
|
attribute_method_suffix("_change_to_be_saved", "_in_database")
|
31
30
|
end
|
32
31
|
|
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
32
|
# <tt>reload</tt> the record and clears changed attributes.
|
49
33
|
def reload(*)
|
50
34
|
super.tap do
|
51
|
-
@
|
52
|
-
|
53
|
-
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
|
54
|
-
end
|
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
|
35
|
+
@mutations_before_last_save = nil
|
36
|
+
@mutations_from_database = nil
|
123
37
|
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
38
|
end
|
130
39
|
|
131
40
|
# Did this attribute change when we last saved? This method can be invoked
|
132
|
-
# as
|
41
|
+
# as +saved_change_to_name?+ instead of <tt>saved_change_to_attribute?("name")</tt>.
|
133
42
|
# Behaves similarly to +attribute_changed?+. This method is useful in
|
134
43
|
# after callbacks to determine if the call to save changed a certain
|
135
44
|
# attribute.
|
@@ -152,8 +61,8 @@ module ActiveRecord
|
|
152
61
|
# Behaves similarly to +attribute_change+. This method is useful in after
|
153
62
|
# callbacks, to see the change in an attribute that just occurred
|
154
63
|
#
|
155
|
-
# This method can be invoked as
|
156
|
-
#
|
64
|
+
# This method can be invoked as +saved_change_to_name+ in instead of
|
65
|
+
# <tt>saved_change_to_attribute("name")</tt>
|
157
66
|
def saved_change_to_attribute(attr_name)
|
158
67
|
mutations_before_last_save.change_to_attribute(attr_name)
|
159
68
|
end
|
@@ -166,7 +75,7 @@ module ActiveRecord
|
|
166
75
|
mutations_before_last_save.original_value(attr_name)
|
167
76
|
end
|
168
77
|
|
169
|
-
# Did the last call to
|
78
|
+
# Did the last call to +save+ have any changes to change?
|
170
79
|
def saved_changes?
|
171
80
|
mutations_before_last_save.any_changes?
|
172
81
|
end
|
@@ -176,116 +85,46 @@ module ActiveRecord
|
|
176
85
|
mutations_before_last_save.changes
|
177
86
|
end
|
178
87
|
|
179
|
-
# Alias for
|
88
|
+
# Alias for +attribute_changed?+
|
180
89
|
def will_save_change_to_attribute?(attr_name, **options)
|
181
90
|
mutations_from_database.changed?(attr_name, **options)
|
182
91
|
end
|
183
92
|
|
184
|
-
# Alias for
|
93
|
+
# Alias for +attribute_change+
|
185
94
|
def attribute_change_to_be_saved(attr_name)
|
186
95
|
mutations_from_database.change_to_attribute(attr_name)
|
187
96
|
end
|
188
97
|
|
189
|
-
# Alias for
|
98
|
+
# Alias for +attribute_was+
|
190
99
|
def attribute_in_database(attr_name)
|
191
100
|
mutations_from_database.original_value(attr_name)
|
192
101
|
end
|
193
102
|
|
194
|
-
# Alias for
|
103
|
+
# Alias for +changed?+
|
195
104
|
def has_changes_to_save?
|
196
105
|
mutations_from_database.any_changes?
|
197
106
|
end
|
198
107
|
|
199
|
-
# Alias for
|
108
|
+
# Alias for +changes+
|
200
109
|
def changes_to_save
|
201
110
|
mutations_from_database.changes
|
202
111
|
end
|
203
112
|
|
204
|
-
# Alias for
|
113
|
+
# Alias for +changed+
|
205
114
|
def changed_attribute_names_to_save
|
206
|
-
|
115
|
+
mutations_from_database.changed_attribute_names
|
207
116
|
end
|
208
117
|
|
209
|
-
# Alias for
|
118
|
+
# Alias for +changed_attributes+
|
210
119
|
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
|
120
|
+
mutations_from_database.changed_values
|
237
121
|
end
|
238
122
|
|
239
123
|
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)
|
288
|
-
end
|
124
|
+
def write_attribute_without_type_cast(attr_name, _)
|
125
|
+
result = super
|
126
|
+
clear_attribute_change(attr_name)
|
127
|
+
result
|
289
128
|
end
|
290
129
|
|
291
130
|
def _update_record(*)
|
@@ -299,35 +138,6 @@ module ActiveRecord
|
|
299
138
|
def keys_for_partial_write
|
300
139
|
changed_attribute_names_to_save & self.class.column_names
|
301
140
|
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
141
|
end
|
332
142
|
end
|
333
143
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "set"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -8,23 +10,22 @@ module ActiveRecord
|
|
8
10
|
# Returns this record's primary key value wrapped in an array if one is
|
9
11
|
# available.
|
10
12
|
def to_key
|
11
|
-
sync_with_transaction_state
|
12
13
|
key = id
|
13
14
|
[key] if key
|
14
15
|
end
|
15
16
|
|
16
17
|
# Returns the primary key value.
|
17
18
|
def id
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
19
|
+
sync_with_transaction_state
|
20
|
+
primary_key = self.class.primary_key
|
21
|
+
_read_attribute(primary_key) if primary_key
|
22
22
|
end
|
23
23
|
|
24
24
|
# Sets the primary key value.
|
25
25
|
def id=(value)
|
26
26
|
sync_with_transaction_state
|
27
|
-
|
27
|
+
primary_key = self.class.primary_key
|
28
|
+
_write_attribute(primary_key, value) if primary_key
|
28
29
|
end
|
29
30
|
|
30
31
|
# Queries the primary key value.
|
@@ -57,16 +58,12 @@ module ActiveRecord
|
|
57
58
|
end
|
58
59
|
|
59
60
|
module ClassMethods
|
60
|
-
|
61
|
-
super
|
61
|
+
ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database).to_set
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
end
|
63
|
+
def instance_method_already_implemented?(method_name)
|
64
|
+
super || primary_key && ID_ATTRIBUTE_METHODS.include?(method_name)
|
66
65
|
end
|
67
66
|
|
68
|
-
ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database).to_set
|
69
|
-
|
70
67
|
def dangerous_attribute_method?(method_name)
|
71
68
|
super && !ID_ATTRIBUTE_METHODS.include?(method_name)
|
72
69
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module AttributeMethods
|
3
5
|
module Read
|
4
6
|
extend ActiveSupport::Concern
|
5
7
|
|
6
|
-
module ClassMethods
|
8
|
+
module ClassMethods # :nodoc:
|
7
9
|
private
|
8
10
|
|
9
11
|
# We want to generate the methods via module_eval rather than
|
@@ -29,9 +31,11 @@ module ActiveRecord
|
|
29
31
|
temp_method = "__temp__#{safe_name}"
|
30
32
|
|
31
33
|
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
|
34
|
+
sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
|
32
35
|
|
33
36
|
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
34
37
|
def #{temp_method}
|
38
|
+
#{sync_with_transaction_state}
|
35
39
|
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
|
36
40
|
_read_attribute(name) { |n| missing_attribute(n, caller) }
|
37
41
|
end
|
@@ -54,7 +58,9 @@ module ActiveRecord
|
|
54
58
|
attr_name.to_s
|
55
59
|
end
|
56
60
|
|
57
|
-
|
61
|
+
primary_key = self.class.primary_key
|
62
|
+
name = primary_key if name == "id".freeze && primary_key
|
63
|
+
sync_with_transaction_state if name == primary_key
|
58
64
|
_read_attribute(name, &block)
|
59
65
|
end
|
60
66
|
|
@@ -1,8 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module AttributeMethods
|
3
5
|
module Serialization
|
4
6
|
extend ActiveSupport::Concern
|
5
7
|
|
8
|
+
class ColumnNotSerializableError < StandardError
|
9
|
+
def initialize(name, type)
|
10
|
+
super <<-EOS.strip_heredoc
|
11
|
+
Column `#{name}` of type #{type.class} does not support `serialize` feature.
|
12
|
+
Usually it means that you are trying to use `serialize`
|
13
|
+
on a column that already implements serialization natively.
|
14
|
+
EOS
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
module ClassMethods
|
7
19
|
# If you have an attribute that needs to be saved to the database as an
|
8
20
|
# object, and retrieved as the same object, then specify the name of that
|
@@ -58,9 +70,20 @@ module ActiveRecord
|
|
58
70
|
end
|
59
71
|
|
60
72
|
decorate_attribute_type(attr_name, :serialize) do |type|
|
73
|
+
if type_incompatible_with_serialize?(type, class_name_or_coder)
|
74
|
+
raise ColumnNotSerializableError.new(attr_name, type)
|
75
|
+
end
|
76
|
+
|
61
77
|
Type::Serialized.new(type, coder)
|
62
78
|
end
|
63
79
|
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def type_incompatible_with_serialize?(type, class_name)
|
84
|
+
type.is_a?(ActiveRecord::Type::Json) && class_name == ::JSON ||
|
85
|
+
type.respond_to?(:type_cast_array, true) && class_name == ::Array
|
86
|
+
end
|
64
87
|
end
|
65
88
|
end
|
66
89
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module AttributeMethods
|
3
5
|
module TimeZoneConversion
|
@@ -54,17 +56,13 @@ module ActiveRecord
|
|
54
56
|
extend ActiveSupport::Concern
|
55
57
|
|
56
58
|
included do
|
57
|
-
mattr_accessor :time_zone_aware_attributes, instance_writer: false
|
58
|
-
self.time_zone_aware_attributes = false
|
59
|
-
|
60
|
-
class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
|
61
|
-
self.skip_time_zone_conversion_for_attributes = []
|
59
|
+
mattr_accessor :time_zone_aware_attributes, instance_writer: false, default: false
|
62
60
|
|
63
|
-
class_attribute :
|
64
|
-
|
61
|
+
class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false, default: []
|
62
|
+
class_attribute :time_zone_aware_types, instance_writer: false, default: [ :datetime, :time ]
|
65
63
|
end
|
66
64
|
|
67
|
-
module ClassMethods
|
65
|
+
module ClassMethods # :nodoc:
|
68
66
|
private
|
69
67
|
|
70
68
|
def inherited(subclass)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module AttributeMethods
|
3
5
|
module Write
|
@@ -7,17 +9,19 @@ module ActiveRecord
|
|
7
9
|
attribute_method_suffix "="
|
8
10
|
end
|
9
11
|
|
10
|
-
module ClassMethods
|
12
|
+
module ClassMethods # :nodoc:
|
11
13
|
private
|
12
14
|
|
13
15
|
def define_method_attribute=(name)
|
14
16
|
safe_name = name.unpack("h*".freeze).first
|
15
17
|
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
|
18
|
+
sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key
|
16
19
|
|
17
20
|
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
18
21
|
def __temp__#{safe_name}=(value)
|
19
22
|
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
|
20
|
-
|
23
|
+
#{sync_with_transaction_state}
|
24
|
+
_write_attribute(name, value)
|
21
25
|
end
|
22
26
|
alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
|
23
27
|
undef_method :__temp__#{safe_name}=
|
@@ -35,30 +39,29 @@ module ActiveRecord
|
|
35
39
|
attr_name.to_s
|
36
40
|
end
|
37
41
|
|
38
|
-
|
42
|
+
primary_key = self.class.primary_key
|
43
|
+
name = primary_key if name == "id".freeze && primary_key
|
44
|
+
sync_with_transaction_state if name == primary_key
|
45
|
+
_write_attribute(name, value)
|
39
46
|
end
|
40
47
|
|
41
|
-
|
42
|
-
|
48
|
+
# This method exists to avoid the expensive primary_key check internally, without
|
49
|
+
# breaking compatibility with the write_attribute API
|
50
|
+
def _write_attribute(attr_name, value) # :nodoc:
|
51
|
+
@attributes.write_from_user(attr_name.to_s, value)
|
52
|
+
value
|
43
53
|
end
|
44
54
|
|
45
55
|
private
|
46
|
-
|
47
|
-
|
48
|
-
|
56
|
+
def write_attribute_without_type_cast(attr_name, value)
|
57
|
+
name = attr_name.to_s
|
58
|
+
@attributes.write_cast_value(name, value)
|
59
|
+
value
|
49
60
|
end
|
50
61
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
if should_type_cast
|
56
|
-
@attributes.write_from_user(attr_name, value)
|
57
|
-
else
|
58
|
-
@attributes.write_cast_value(attr_name, value)
|
59
|
-
end
|
60
|
-
|
61
|
-
value
|
62
|
+
# Handle *= for method_missing.
|
63
|
+
def attribute=(attribute_name, value)
|
64
|
+
_write_attribute(attribute_name, value)
|
62
65
|
end
|
63
66
|
end
|
64
67
|
end
|
@@ -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,46 @@ 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
|
+
# "#{column_name}"
|
179
|
+
# "#{column_name} #{direction}"
|
180
|
+
COLUMN_NAME_ORDER_WHITELIST = /\A(?:\w+\.)?\w+(?:\s+asc|\s+desc)?\z/i
|
181
|
+
|
182
|
+
def enforce_raw_sql_whitelist(args, whitelist: COLUMN_NAME_WHITELIST) # :nodoc:
|
183
|
+
unexpected = args.reject do |arg|
|
184
|
+
arg.kind_of?(Arel::Node) ||
|
185
|
+
arg.is_a?(Arel::Nodes::SqlLiteral) ||
|
186
|
+
arg.is_a?(Arel::Attributes::Attribute) ||
|
187
|
+
arg.to_s.split(/\s*,\s*/).all? { |part| whitelist.match?(part) }
|
188
|
+
end
|
189
|
+
|
190
|
+
return if unexpected.none?
|
191
|
+
|
192
|
+
if allow_unsafe_raw_sql == :deprecated
|
193
|
+
ActiveSupport::Deprecation.warn(
|
194
|
+
"Dangerous query method (method whose arguments are used as raw " \
|
195
|
+
"SQL) called with non-attribute argument(s): " \
|
196
|
+
"#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
|
197
|
+
"arguments will be disallowed in Rails 6.0. This method should " \
|
198
|
+
"not be called with user-provided values, such as request " \
|
199
|
+
"parameters or model attributes. Known-safe values can be passed " \
|
200
|
+
"by wrapping them in Arel.sql()."
|
201
|
+
)
|
202
|
+
else
|
203
|
+
raise(ActiveRecord::UnknownAttributeReference,
|
204
|
+
"Query method called with non-attribute argument(s): " +
|
205
|
+
unexpected.map(&:inspect).join(", ")
|
206
|
+
)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
170
210
|
# Returns true if the given attribute exists, otherwise false.
|
171
211
|
#
|
172
212
|
# class Person < ActiveRecord::Base
|
@@ -236,7 +276,7 @@ module ActiveRecord
|
|
236
276
|
return has_attribute?(name)
|
237
277
|
end
|
238
278
|
|
239
|
-
|
279
|
+
true
|
240
280
|
end
|
241
281
|
|
242
282
|
# Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
|
@@ -416,7 +456,7 @@ module ActiveRecord
|
|
416
456
|
arel_table = self.class.arel_table
|
417
457
|
|
418
458
|
attribute_names.each do |name|
|
419
|
-
attrs[arel_table[name]] =
|
459
|
+
attrs[arel_table[name]] = _read_attribute(name)
|
420
460
|
end
|
421
461
|
attrs
|
422
462
|
end
|
@@ -443,9 +483,5 @@ module ActiveRecord
|
|
443
483
|
def pk_attribute?(name)
|
444
484
|
name == self.class.primary_key
|
445
485
|
end
|
446
|
-
|
447
|
-
def typecasted_attribute_value(name)
|
448
|
-
_read_attribute(name)
|
449
|
-
end
|
450
486
|
end
|
451
487
|
end
|