activerecord 5.1.7 → 5.2.6
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 +583 -673
- 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/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +41 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +27 -8
- 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 +12 -4
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- 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 +59 -47
- data/lib/active_record/associations/collection_proxy.rb +20 -49
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +12 -1
- data/lib/active_record/associations/has_many_through_association.rb +36 -30
- data/lib/active_record/associations/has_one_association.rb +12 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
- 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/join_dependency.rb +48 -93
- data/lib/active_record/associations/preloader/association.rb +45 -61
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/preloader.rb +18 -38
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +40 -63
- data/lib/active_record/attribute_assignment.rb +2 -5
- 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 +30 -214
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- 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 +21 -9
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attributes.rb +6 -5
- data/lib/active_record/autosave_association.rb +35 -19
- 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 +12 -8
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
- data/lib/active_record/connection_adapters/column.rb +3 -1
- 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 +47 -2
- 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 -30
- 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 +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- 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.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 +2 -0
- 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 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
- 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 +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
- 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 +233 -111
- 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 +57 -73
- 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 +22 -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 +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +81 -94
- 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 +10 -3
- 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 +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 +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 +14 -17
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +43 -0
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +47 -9
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/model_schema.rb +16 -21
- 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 +167 -16
- data/lib/active_record/query_cache.rb +6 -8
- data/lib/active_record/querying.rb +4 -2
- 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 +46 -36
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +108 -194
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/calculations.rb +45 -19
- data/lib/active_record/relation/delegation.rb +45 -27
- data/lib/active_record/relation/finder_methods.rb +75 -76
- 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/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/predicate_builder.rb +60 -79
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +128 -99
- 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 -68
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +120 -214
- 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 +8 -9
- data/lib/active_record/scoping/named.rb +23 -7
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +23 -13
- 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 +25 -14
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +33 -28
- 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 +23 -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/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -122
- data/lib/active_record/attribute_set/builder.rb +0 -126
- 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 -37
@@ -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
|
|
@@ -63,7 +69,7 @@ module ActiveRecord
|
|
63
69
|
if defined?(JRUBY_VERSION)
|
64
70
|
# This form is significantly faster on JRuby, and this is one of our biggest hotspots.
|
65
71
|
# https://github.com/jruby/jruby/pull/2562
|
66
|
-
def _read_attribute(attr_name, &block) # :nodoc
|
72
|
+
def _read_attribute(attr_name, &block) # :nodoc:
|
67
73
|
@attributes.fetch_value(attr_name.to_s, &block)
|
68
74
|
end
|
69
75
|
else
|
@@ -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,21 +39,29 @@ module ActiveRecord
|
|
35
39
|
attr_name.to_s
|
36
40
|
end
|
37
41
|
|
38
|
-
|
39
|
-
|
40
|
-
|
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)
|
41
46
|
end
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
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)
|
46
52
|
value
|
47
53
|
end
|
48
54
|
|
49
55
|
private
|
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
|
60
|
+
end
|
61
|
+
|
50
62
|
# Handle *= for method_missing.
|
51
63
|
def attribute=(attribute_name, value)
|
52
|
-
|
64
|
+
_write_attribute(attribute_name, value)
|
53
65
|
end
|
54
66
|
end
|
55
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,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,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_model/attribute/user_provided_default"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
# See ActiveRecord::Attributes::ClassMethods for documentation
|
@@ -6,8 +8,7 @@ module ActiveRecord
|
|
6
8
|
extend ActiveSupport::Concern
|
7
9
|
|
8
10
|
included do
|
9
|
-
class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false # :internal:
|
10
|
-
self.attributes_to_define_after_schema_loads = {}
|
11
|
+
class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false, default: {} # :internal:
|
11
12
|
end
|
12
13
|
|
13
14
|
module ClassMethods
|
@@ -249,14 +250,14 @@ module ActiveRecord
|
|
249
250
|
if value == NO_DEFAULT_PROVIDED
|
250
251
|
default_attribute = _default_attributes[name].with_type(type)
|
251
252
|
elsif from_user
|
252
|
-
default_attribute = Attribute::UserProvidedDefault.new(
|
253
|
+
default_attribute = ActiveModel::Attribute::UserProvidedDefault.new(
|
253
254
|
name,
|
254
255
|
value,
|
255
256
|
type,
|
256
257
|
_default_attributes.fetch(name.to_s) { nil },
|
257
258
|
)
|
258
259
|
else
|
259
|
-
default_attribute = Attribute.from_database(name, value, type)
|
260
|
+
default_attribute = ActiveModel::Attribute.from_database(name, value, type)
|
260
261
|
end
|
261
262
|
_default_attributes[name] = default_attribute
|
262
263
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
# = Active Record Autosave Association
|
3
5
|
#
|
@@ -140,8 +142,7 @@ module ActiveRecord
|
|
140
142
|
|
141
143
|
included do
|
142
144
|
Associations::Builder::Association.extensions << AssociationBuilderExtension
|
143
|
-
mattr_accessor :index_nested_attribute_errors, instance_writer: false
|
144
|
-
self.index_nested_attribute_errors = false
|
145
|
+
mattr_accessor :index_nested_attribute_errors, instance_writer: false, default: false
|
145
146
|
end
|
146
147
|
|
147
148
|
module ClassMethods # :nodoc:
|
@@ -216,13 +217,7 @@ module ActiveRecord
|
|
216
217
|
method = :validate_single_association
|
217
218
|
end
|
218
219
|
|
219
|
-
define_non_cyclic_method(validation_method)
|
220
|
-
send(method, reflection)
|
221
|
-
# TODO: remove the following line as soon as the return value of
|
222
|
-
# callbacks is ignored, that is, returning `false` does not
|
223
|
-
# display a deprecation warning or halts the callback chain.
|
224
|
-
true
|
225
|
-
end
|
220
|
+
define_non_cyclic_method(validation_method) { send(method, reflection) }
|
226
221
|
validate validation_method
|
227
222
|
after_validation :_ensure_no_duplicate_errors
|
228
223
|
end
|
@@ -277,7 +272,7 @@ module ActiveRecord
|
|
277
272
|
# or saved. If +autosave+ is +false+ only new records will be returned,
|
278
273
|
# unless the parent is/was a new record itself.
|
279
274
|
def associated_records_to_validate_or_save(association, new_record, autosave)
|
280
|
-
if new_record
|
275
|
+
if new_record || custom_validation_context?
|
281
276
|
association && association.target
|
282
277
|
elsif autosave
|
283
278
|
association.target.find_all(&:changed_for_autosave?)
|
@@ -309,7 +304,7 @@ module ActiveRecord
|
|
309
304
|
def validate_single_association(reflection)
|
310
305
|
association = association_instance_get(reflection.name)
|
311
306
|
record = association && association.reader
|
312
|
-
association_valid?(reflection, record) if record
|
307
|
+
association_valid?(reflection, record) if record && (record.changed_for_autosave? || custom_validation_context?)
|
313
308
|
end
|
314
309
|
|
315
310
|
# Validate the associated records if <tt>:validate</tt> or
|
@@ -329,7 +324,7 @@ module ActiveRecord
|
|
329
324
|
def association_valid?(reflection, record, index = nil)
|
330
325
|
return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
|
331
326
|
|
332
|
-
context = validation_context
|
327
|
+
context = validation_context if custom_validation_context?
|
333
328
|
|
334
329
|
unless valid = record.valid?(context)
|
335
330
|
if reflection.options[:autosave]
|
@@ -369,7 +364,6 @@ module ActiveRecord
|
|
369
364
|
# association whether or not the parent was a new record before saving.
|
370
365
|
def before_save_collection_association
|
371
366
|
@new_record_before_save = new_record?
|
372
|
-
true
|
373
367
|
end
|
374
368
|
|
375
369
|
def after_save_collection_association
|
@@ -388,10 +382,14 @@ module ActiveRecord
|
|
388
382
|
if association = association_instance_get(reflection.name)
|
389
383
|
autosave = reflection.options[:autosave]
|
390
384
|
|
385
|
+
# By saving the instance variable in a local variable,
|
386
|
+
# we make the whole callback re-entrant.
|
387
|
+
new_record_before_save = @new_record_before_save
|
388
|
+
|
391
389
|
# reconstruct the scope now that we know the owner's id
|
392
|
-
association.reset_scope
|
390
|
+
association.reset_scope
|
393
391
|
|
394
|
-
if records = associated_records_to_validate_or_save(association,
|
392
|
+
if records = associated_records_to_validate_or_save(association, new_record_before_save, autosave)
|
395
393
|
if autosave
|
396
394
|
records_to_destroy = records.select(&:marked_for_destruction?)
|
397
395
|
records_to_destroy.each { |record| association.destroy(record) }
|
@@ -403,11 +401,16 @@ module ActiveRecord
|
|
403
401
|
|
404
402
|
saved = true
|
405
403
|
|
406
|
-
if autosave != false && (
|
404
|
+
if autosave != false && (new_record_before_save || record.new_record?)
|
407
405
|
if autosave
|
408
406
|
saved = association.insert_record(record, false)
|
409
|
-
|
410
|
-
association.insert_record(record)
|
407
|
+
elsif !reflection.nested?
|
408
|
+
association_saved = association.insert_record(record)
|
409
|
+
|
410
|
+
if reflection.validate?
|
411
|
+
errors.add(reflection.name) unless association_saved
|
412
|
+
saved = association_saved
|
413
|
+
end
|
411
414
|
end
|
412
415
|
elsif autosave
|
413
416
|
saved = record.save(validate: false)
|
@@ -442,6 +445,9 @@ module ActiveRecord
|
|
442
445
|
if (autosave && record.changed_for_autosave?) || new_record? || record_changed?(reflection, record, key)
|
443
446
|
unless reflection.through_reflection
|
444
447
|
record[reflection.foreign_key] = key
|
448
|
+
if inverse_reflection = reflection.inverse_of
|
449
|
+
record.association(inverse_reflection.name).loaded!
|
450
|
+
end
|
445
451
|
end
|
446
452
|
|
447
453
|
saved = record.save(validate: !autosave)
|
@@ -455,10 +461,16 @@ module ActiveRecord
|
|
455
461
|
# If the record is new or it has changed, returns true.
|
456
462
|
def record_changed?(reflection, record, key)
|
457
463
|
record.new_record? ||
|
458
|
-
|
464
|
+
association_foreign_key_changed?(reflection, record, key) ||
|
459
465
|
record.will_save_change_to_attribute?(reflection.foreign_key)
|
460
466
|
end
|
461
467
|
|
468
|
+
def association_foreign_key_changed?(reflection, record, key)
|
469
|
+
return false if reflection.through_reflection?
|
470
|
+
|
471
|
+
record.has_attribute?(reflection.foreign_key) && record[reflection.foreign_key] != key
|
472
|
+
end
|
473
|
+
|
462
474
|
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
463
475
|
#
|
464
476
|
# In addition, it will destroy the association if it was marked for destruction.
|
@@ -487,6 +499,10 @@ module ActiveRecord
|
|
487
499
|
end
|
488
500
|
end
|
489
501
|
|
502
|
+
def custom_validation_context?
|
503
|
+
validation_context && [:create, :update].exclude?(validation_context)
|
504
|
+
end
|
505
|
+
|
490
506
|
def _ensure_no_duplicate_errors
|
491
507
|
errors.messages.each_key do |attribute|
|
492
508
|
errors[attribute].uniq!
|
data/lib/active_record/base.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
# = Active Record \Callbacks
|
3
5
|
#
|
@@ -96,9 +98,9 @@ module ActiveRecord
|
|
96
98
|
# == Types of callbacks
|
97
99
|
#
|
98
100
|
# There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
|
99
|
-
# inline methods (using a proc)
|
101
|
+
# inline methods (using a proc). Method references and callback objects
|
100
102
|
# are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for
|
101
|
-
# creating mix-ins)
|
103
|
+
# creating mix-ins).
|
102
104
|
#
|
103
105
|
# The method reference callbacks work by specifying a protected or private method available in the object, like this:
|
104
106
|
#
|
@@ -230,7 +232,7 @@ module ActiveRecord
|
|
230
232
|
#
|
231
233
|
# For example:
|
232
234
|
#
|
233
|
-
# class Topic
|
235
|
+
# class Topic < ActiveRecord::Base
|
234
236
|
# has_many :children
|
235
237
|
#
|
236
238
|
# after_save :log_children
|
@@ -238,7 +240,7 @@ module ActiveRecord
|
|
238
240
|
#
|
239
241
|
# private
|
240
242
|
#
|
241
|
-
# def
|
243
|
+
# def log_children
|
242
244
|
# # Child processing
|
243
245
|
# end
|
244
246
|
#
|
@@ -255,7 +257,7 @@ module ActiveRecord
|
|
255
257
|
#
|
256
258
|
# For example:
|
257
259
|
#
|
258
|
-
# class Topic
|
260
|
+
# class Topic < ActiveRecord::Base
|
259
261
|
# has_many :children
|
260
262
|
#
|
261
263
|
# after_commit :log_children
|
@@ -263,7 +265,7 @@ module ActiveRecord
|
|
263
265
|
#
|
264
266
|
# private
|
265
267
|
#
|
266
|
-
# def
|
268
|
+
# def log_children
|
267
269
|
# # Child processing
|
268
270
|
# end
|
269
271
|
#
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module CollectionCacheKey
|
3
5
|
def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
|
4
|
-
query_signature = Digest
|
6
|
+
query_signature = ActiveSupport::Digest.hexdigest(collection.to_sql)
|
5
7
|
key = "#{collection.model_name.cache_key}/query-#{query_signature}"
|
6
8
|
|
7
9
|
if collection.loaded? || collection.distinct_value
|
@@ -10,24 +12,26 @@ module ActiveRecord
|
|
10
12
|
timestamp = collection.max_by(×tamp_column)._read_attribute(timestamp_column)
|
11
13
|
end
|
12
14
|
else
|
13
|
-
|
14
|
-
|
15
|
+
if collection.eager_loading?
|
16
|
+
collection = collection.send(:apply_join_dependency)
|
17
|
+
end
|
18
|
+
column_type = type_for_attribute(timestamp_column)
|
19
|
+
column = connection.column_name_from_arel_node(collection.arel_attribute(timestamp_column))
|
15
20
|
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
|
16
21
|
|
17
22
|
if collection.has_limit_or_offset?
|
18
|
-
query = collection.
|
19
|
-
query.select_values = [column]
|
23
|
+
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
20
24
|
subquery_alias = "subquery_for_cache_key"
|
21
|
-
subquery_column = "#{subquery_alias}
|
25
|
+
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
|
22
26
|
subquery = query.arel.as(subquery_alias)
|
23
|
-
arel = Arel::SelectManager.new(
|
27
|
+
arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
|
24
28
|
else
|
25
29
|
query = collection.unscope(:order)
|
26
30
|
query.select_values = [select_values % column]
|
27
31
|
arel = query.arel
|
28
32
|
end
|
29
33
|
|
30
|
-
result = connection.select_one(arel, nil
|
34
|
+
result = connection.select_one(arel, nil)
|
31
35
|
|
32
36
|
if result.blank?
|
33
37
|
size = 0
|