activerecord 5.2.2.1 → 6.0.2
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 +734 -508
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +20 -15
- data/lib/active_record/associations/association.rb +61 -20
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +16 -28
- data/lib/active_record/associations/collection_proxy.rb +19 -48
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +3 -10
- data/lib/active_record/associations/has_many_through_association.rb +20 -25
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +28 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +22 -8
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +137 -26
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +114 -130
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +26 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +135 -56
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +189 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +151 -198
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +7 -11
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -77
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +131 -143
- data/lib/active_record/connection_handling.rb +155 -26
- data/lib/active_record/core.rb +104 -59
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +30 -16
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +91 -64
- data/lib/active_record/model_schema.rb +33 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +231 -25
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -22
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +42 -44
- data/lib/active_record/relation.rb +311 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +67 -57
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +28 -28
- data/lib/active_record/relation/merger.rb +17 -23
- data/lib/active_record/relation/predicate_builder.rb +18 -15
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +17 -10
- data/lib/active_record/relation/query_methods.rb +247 -73
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +20 -15
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +58 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +111 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -14,41 +14,34 @@ module ActiveRecord
|
|
14
14
|
[key] if key
|
15
15
|
end
|
16
16
|
|
17
|
-
# Returns the primary key value.
|
17
|
+
# Returns the primary key column's value.
|
18
18
|
def id
|
19
|
-
|
20
|
-
primary_key = self.class.primary_key
|
21
|
-
_read_attribute(primary_key) if primary_key
|
19
|
+
_read_attribute(@primary_key)
|
22
20
|
end
|
23
21
|
|
24
|
-
# Sets the primary key value.
|
22
|
+
# Sets the primary key column's value.
|
25
23
|
def id=(value)
|
26
|
-
|
27
|
-
primary_key = self.class.primary_key
|
28
|
-
_write_attribute(primary_key, value) if primary_key
|
24
|
+
_write_attribute(@primary_key, value)
|
29
25
|
end
|
30
26
|
|
31
|
-
# Queries the primary key value.
|
27
|
+
# Queries the primary key column's value.
|
32
28
|
def id?
|
33
|
-
|
34
|
-
query_attribute(self.class.primary_key)
|
29
|
+
query_attribute(@primary_key)
|
35
30
|
end
|
36
31
|
|
37
|
-
# Returns the primary key value before type cast.
|
32
|
+
# Returns the primary key column's value before type cast.
|
38
33
|
def id_before_type_cast
|
39
|
-
|
40
|
-
read_attribute_before_type_cast(self.class.primary_key)
|
34
|
+
read_attribute_before_type_cast(@primary_key)
|
41
35
|
end
|
42
36
|
|
43
|
-
# Returns the primary key previous value.
|
37
|
+
# Returns the primary key column's previous value.
|
44
38
|
def id_was
|
45
|
-
|
46
|
-
attribute_was(self.class.primary_key)
|
39
|
+
attribute_was(@primary_key)
|
47
40
|
end
|
48
41
|
|
42
|
+
# Returns the primary key column's value from the database.
|
49
43
|
def id_in_database
|
50
|
-
|
51
|
-
attribute_in_database(self.class.primary_key)
|
44
|
+
attribute_in_database(@primary_key)
|
52
45
|
end
|
53
46
|
|
54
47
|
private
|
@@ -83,7 +76,7 @@ module ActiveRecord
|
|
83
76
|
end
|
84
77
|
|
85
78
|
def reset_primary_key #:nodoc:
|
86
|
-
if
|
79
|
+
if base_class?
|
87
80
|
self.primary_key = get_primary_key(base_class.name)
|
88
81
|
else
|
89
82
|
self.primary_key = base_class.primary_key
|
@@ -121,7 +114,7 @@ module ActiveRecord
|
|
121
114
|
#
|
122
115
|
# Project.primary_key # => "foo_id"
|
123
116
|
def primary_key=(value)
|
124
|
-
@primary_key = value && value.to_s
|
117
|
+
@primary_key = value && -value.to_s
|
125
118
|
@quoted_primary_key = nil
|
126
119
|
@attributes_builder = nil
|
127
120
|
end
|
@@ -131,7 +124,7 @@ module ActiveRecord
|
|
131
124
|
def suppress_composite_primary_key(pk)
|
132
125
|
return pk unless pk.is_a?(Array)
|
133
126
|
|
134
|
-
warn
|
127
|
+
warn <<~WARNING
|
135
128
|
WARNING: Active Record does not support composite primary key.
|
136
129
|
|
137
130
|
#{table_name} has composite primary key. Composite primary key is ignored.
|
@@ -16,8 +16,7 @@ module ActiveRecord
|
|
16
16
|
when true then true
|
17
17
|
when false, nil then false
|
18
18
|
else
|
19
|
-
|
20
|
-
if column.nil?
|
19
|
+
if !type_for_attribute(attr_name) { false }
|
21
20
|
if Numeric === value || value !~ /[^0-9]/
|
22
21
|
!value.to_i.zero?
|
23
22
|
else
|
@@ -33,7 +32,7 @@ module ActiveRecord
|
|
33
32
|
end
|
34
33
|
|
35
34
|
private
|
36
|
-
#
|
35
|
+
# Dispatch target for <tt>*?</tt> attribute methods.
|
37
36
|
def attribute?(attribute_name)
|
38
37
|
query_attribute(attribute_name)
|
39
38
|
end
|
@@ -8,42 +8,16 @@ module ActiveRecord
|
|
8
8
|
module ClassMethods # :nodoc:
|
9
9
|
private
|
10
10
|
|
11
|
-
# We want to generate the methods via module_eval rather than
|
12
|
-
# define_method, because define_method is slower on dispatch.
|
13
|
-
# Evaluating many similar methods may use more memory as the instruction
|
14
|
-
# sequences are duplicated and cached (in MRI). define_method may
|
15
|
-
# be slower on dispatch, but if you're careful about the closure
|
16
|
-
# created, then define_method will consume much less memory.
|
17
|
-
#
|
18
|
-
# But sometimes the database might return columns with
|
19
|
-
# characters that are not allowed in normal method names (like
|
20
|
-
# 'my_column(omg)'. So to work around this we first define with
|
21
|
-
# the __temp__ identifier, and then use alias method to rename
|
22
|
-
# it to what we want.
|
23
|
-
#
|
24
|
-
# We are also defining a constant to hold the frozen string of
|
25
|
-
# the attribute name. Using a constant means that we do not have
|
26
|
-
# to allocate an object on each call to the attribute method.
|
27
|
-
# Making it frozen means that it doesn't get duped when used to
|
28
|
-
# key the @attributes in read_attribute.
|
29
11
|
def define_method_attribute(name)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
|
40
|
-
_read_attribute(name) { |n| missing_attribute(n, caller) }
|
41
|
-
end
|
42
|
-
STR
|
43
|
-
|
44
|
-
generated_attribute_methods.module_eval do
|
45
|
-
alias_method name, temp_method
|
46
|
-
undef_method temp_method
|
12
|
+
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
13
|
+
generated_attribute_methods, name
|
14
|
+
) do |temp_method_name, attr_name_expr|
|
15
|
+
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
16
|
+
def #{temp_method_name}
|
17
|
+
name = #{attr_name_expr}
|
18
|
+
_read_attribute(name) { |n| missing_attribute(n, caller) }
|
19
|
+
end
|
20
|
+
RUBY
|
47
21
|
end
|
48
22
|
end
|
49
23
|
end
|
@@ -52,30 +26,18 @@ module ActiveRecord
|
|
52
26
|
# it has been typecast (for example, "2004-12-12" in a date column is cast
|
53
27
|
# to a date object, like Date.new(2004, 12, 12)).
|
54
28
|
def read_attribute(attr_name, &block)
|
55
|
-
name =
|
56
|
-
|
57
|
-
else
|
58
|
-
attr_name.to_s
|
59
|
-
end
|
29
|
+
name = attr_name.to_s
|
30
|
+
name = self.class.attribute_aliases[name] || name
|
60
31
|
|
61
|
-
|
62
|
-
name = primary_key if name == "id".freeze && primary_key
|
63
|
-
sync_with_transaction_state if name == primary_key
|
32
|
+
name = @primary_key if name == "id" && @primary_key
|
64
33
|
_read_attribute(name, &block)
|
65
34
|
end
|
66
35
|
|
67
36
|
# This method exists to avoid the expensive primary_key check internally, without
|
68
37
|
# breaking compatibility with the read_attribute API
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
def _read_attribute(attr_name, &block) # :nodoc:
|
73
|
-
@attributes.fetch_value(attr_name.to_s, &block)
|
74
|
-
end
|
75
|
-
else
|
76
|
-
def _read_attribute(attr_name) # :nodoc:
|
77
|
-
@attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
|
78
|
-
end
|
38
|
+
def _read_attribute(attr_name, &block) # :nodoc
|
39
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
40
|
+
@attributes.fetch_value(attr_name.to_s, &block)
|
79
41
|
end
|
80
42
|
|
81
43
|
alias :attribute :_read_attribute
|
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
|
8
8
|
class ColumnNotSerializableError < StandardError
|
9
9
|
def initialize(name, type)
|
10
|
-
super
|
10
|
+
super <<~EOS
|
11
11
|
Column `#{name}` of type #{type.class} does not support `serialize` feature.
|
12
12
|
Usually it means that you are trying to use `serialize`
|
13
13
|
on a column that already implements serialization natively.
|
@@ -73,7 +73,7 @@ module ActiveRecord
|
|
73
73
|
# `skip_time_zone_conversion_for_attributes` would not be picked up.
|
74
74
|
subclass.class_eval do
|
75
75
|
matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
|
76
|
-
decorate_matching_attribute_types(matcher,
|
76
|
+
decorate_matching_attribute_types(matcher, "_time_zone_conversion") do |type|
|
77
77
|
TimeZoneConverter.new(type)
|
78
78
|
end
|
79
79
|
end
|
@@ -13,19 +13,16 @@ module ActiveRecord
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def define_method_attribute=(name)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
|
27
|
-
undef_method :__temp__#{safe_name}=
|
28
|
-
STR
|
16
|
+
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
17
|
+
generated_attribute_methods, name, writer: true,
|
18
|
+
) do |temp_method_name, attr_name_expr|
|
19
|
+
generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
20
|
+
def #{temp_method_name}(value)
|
21
|
+
name = #{attr_name_expr}
|
22
|
+
_write_attribute(name, value)
|
23
|
+
end
|
24
|
+
RUBY
|
25
|
+
end
|
29
26
|
end
|
30
27
|
end
|
31
28
|
|
@@ -33,33 +30,29 @@ module ActiveRecord
|
|
33
30
|
# specified +value+. Empty strings for Integer and Float columns are
|
34
31
|
# turned into +nil+.
|
35
32
|
def write_attribute(attr_name, value)
|
36
|
-
name =
|
37
|
-
|
38
|
-
else
|
39
|
-
attr_name.to_s
|
40
|
-
end
|
33
|
+
name = attr_name.to_s
|
34
|
+
name = self.class.attribute_aliases[name] || name
|
41
35
|
|
42
|
-
|
43
|
-
name = primary_key if name == "id".freeze && primary_key
|
44
|
-
sync_with_transaction_state if name == primary_key
|
36
|
+
name = @primary_key if name == "id" && @primary_key
|
45
37
|
_write_attribute(name, value)
|
46
38
|
end
|
47
39
|
|
48
40
|
# This method exists to avoid the expensive primary_key check internally, without
|
49
41
|
# breaking compatibility with the write_attribute API
|
50
42
|
def _write_attribute(attr_name, value) # :nodoc:
|
43
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
51
44
|
@attributes.write_from_user(attr_name.to_s, value)
|
52
45
|
value
|
53
46
|
end
|
54
47
|
|
55
48
|
private
|
56
49
|
def write_attribute_without_type_cast(attr_name, value)
|
57
|
-
|
58
|
-
@attributes.write_cast_value(
|
50
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
51
|
+
@attributes.write_cast_value(attr_name.to_s, value)
|
59
52
|
value
|
60
53
|
end
|
61
54
|
|
62
|
-
#
|
55
|
+
# Dispatch target for <tt>*=</tt> attribute methods.
|
63
56
|
def attribute=(attribute_name, value)
|
64
57
|
_write_attribute(attribute_name, value)
|
65
58
|
end
|
@@ -41,6 +41,9 @@ module ActiveRecord
|
|
41
41
|
# +range+ (PostgreSQL only) specifies that the type should be a range (see the
|
42
42
|
# examples below).
|
43
43
|
#
|
44
|
+
# When using a symbol for +cast_type+, extra options are forwarded to the
|
45
|
+
# constructor of the type object.
|
46
|
+
#
|
44
47
|
# ==== Examples
|
45
48
|
#
|
46
49
|
# The type detected by Active Record can be overridden.
|
@@ -112,6 +115,16 @@ module ActiveRecord
|
|
112
115
|
# my_float_range: 1.0..3.5
|
113
116
|
# }
|
114
117
|
#
|
118
|
+
# Passing options to the type constructor
|
119
|
+
#
|
120
|
+
# # app/models/my_model.rb
|
121
|
+
# class MyModel < ActiveRecord::Base
|
122
|
+
# attribute :small_int, :integer, limit: 2
|
123
|
+
# end
|
124
|
+
#
|
125
|
+
# MyModel.create(small_int: 65537)
|
126
|
+
# # => Error: 65537 is out of range for the limit of two bytes
|
127
|
+
#
|
115
128
|
# ==== Creating Custom Types
|
116
129
|
#
|
117
130
|
# Users may also define their own custom types, as long as they respond
|
@@ -149,7 +149,7 @@ module ActiveRecord
|
|
149
149
|
private
|
150
150
|
|
151
151
|
def define_non_cyclic_method(name, &block)
|
152
|
-
return if
|
152
|
+
return if instance_methods(false).include?(name)
|
153
153
|
define_method(name) do |*args|
|
154
154
|
result = true; @_already_called ||= {}
|
155
155
|
# Loop prevention for validation of associations
|
@@ -272,7 +272,7 @@ module ActiveRecord
|
|
272
272
|
# or saved. If +autosave+ is +false+ only new records will be returned,
|
273
273
|
# unless the parent is/was a new record itself.
|
274
274
|
def associated_records_to_validate_or_save(association, new_record, autosave)
|
275
|
-
if new_record
|
275
|
+
if new_record || custom_validation_context?
|
276
276
|
association && association.target
|
277
277
|
elsif autosave
|
278
278
|
association.target.find_all(&:changed_for_autosave?)
|
@@ -304,7 +304,7 @@ module ActiveRecord
|
|
304
304
|
def validate_single_association(reflection)
|
305
305
|
association = association_instance_get(reflection.name)
|
306
306
|
record = association && association.reader
|
307
|
-
association_valid?(reflection, record) if record
|
307
|
+
association_valid?(reflection, record) if record && (record.changed_for_autosave? || custom_validation_context?)
|
308
308
|
end
|
309
309
|
|
310
310
|
# Validate the associated records if <tt>:validate</tt> or
|
@@ -324,7 +324,7 @@ module ActiveRecord
|
|
324
324
|
def association_valid?(reflection, record, index = nil)
|
325
325
|
return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
|
326
326
|
|
327
|
-
context = validation_context
|
327
|
+
context = validation_context if custom_validation_context?
|
328
328
|
|
329
329
|
unless valid = record.valid?(context)
|
330
330
|
if reflection.options[:autosave]
|
@@ -382,10 +382,14 @@ module ActiveRecord
|
|
382
382
|
if association = association_instance_get(reflection.name)
|
383
383
|
autosave = reflection.options[:autosave]
|
384
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
|
+
|
385
389
|
# reconstruct the scope now that we know the owner's id
|
386
390
|
association.reset_scope
|
387
391
|
|
388
|
-
if records = associated_records_to_validate_or_save(association,
|
392
|
+
if records = associated_records_to_validate_or_save(association, new_record_before_save, autosave)
|
389
393
|
if autosave
|
390
394
|
records_to_destroy = records.select(&:marked_for_destruction?)
|
391
395
|
records_to_destroy.each { |record| association.destroy(record) }
|
@@ -397,7 +401,7 @@ module ActiveRecord
|
|
397
401
|
|
398
402
|
saved = true
|
399
403
|
|
400
|
-
if autosave != false && (
|
404
|
+
if autosave != false && (new_record_before_save || record.new_record?)
|
401
405
|
if autosave
|
402
406
|
saved = association.insert_record(record, false)
|
403
407
|
elsif !reflection.nested?
|
@@ -412,7 +416,7 @@ module ActiveRecord
|
|
412
416
|
saved = record.save(validate: false)
|
413
417
|
end
|
414
418
|
|
415
|
-
raise
|
419
|
+
raise(RecordInvalid.new(association.owner)) unless saved
|
416
420
|
end
|
417
421
|
end
|
418
422
|
end
|
@@ -457,10 +461,16 @@ module ActiveRecord
|
|
457
461
|
# If the record is new or it has changed, returns true.
|
458
462
|
def record_changed?(reflection, record, key)
|
459
463
|
record.new_record? ||
|
460
|
-
|
464
|
+
association_foreign_key_changed?(reflection, record, key) ||
|
461
465
|
record.will_save_change_to_attribute?(reflection.foreign_key)
|
462
466
|
end
|
463
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
|
+
|
464
474
|
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
465
475
|
#
|
466
476
|
# In addition, it will destroy the association if it was marked for destruction.
|
@@ -489,6 +499,10 @@ module ActiveRecord
|
|
489
499
|
end
|
490
500
|
end
|
491
501
|
|
502
|
+
def custom_validation_context?
|
503
|
+
validation_context && [:create, :update].exclude?(validation_context)
|
504
|
+
end
|
505
|
+
|
492
506
|
def _ensure_no_duplicate_errors
|
493
507
|
errors.messages.each_key do |attribute|
|
494
508
|
errors[attribute].uniq!
|
data/lib/active_record/base.rb
CHANGED
@@ -9,7 +9,6 @@ require "active_support/core_ext/module/attribute_accessors"
|
|
9
9
|
require "active_support/core_ext/array/extract_options"
|
10
10
|
require "active_support/core_ext/hash/deep_merge"
|
11
11
|
require "active_support/core_ext/hash/slice"
|
12
|
-
require "active_support/core_ext/hash/transform_values"
|
13
12
|
require "active_support/core_ext/string/behavior"
|
14
13
|
require "active_support/core_ext/kernel/singleton_class"
|
15
14
|
require "active_support/core_ext/module/introspection"
|
@@ -23,6 +22,7 @@ require "active_record/explain_subscriber"
|
|
23
22
|
require "active_record/relation/delegation"
|
24
23
|
require "active_record/attributes"
|
25
24
|
require "active_record/type_caster"
|
25
|
+
require "active_record/database_configurations"
|
26
26
|
|
27
27
|
module ActiveRecord #:nodoc:
|
28
28
|
# = Active Record
|
@@ -288,7 +288,7 @@ module ActiveRecord #:nodoc:
|
|
288
288
|
extend Explain
|
289
289
|
extend Enum
|
290
290
|
extend Delegation::DelegateCache
|
291
|
-
extend
|
291
|
+
extend Aggregations::ClassMethods
|
292
292
|
|
293
293
|
include Core
|
294
294
|
include Persistence
|
@@ -314,7 +314,6 @@ module ActiveRecord #:nodoc:
|
|
314
314
|
include ActiveModel::SecurePassword
|
315
315
|
include AutosaveAssociation
|
316
316
|
include NestedAttributes
|
317
|
-
include Aggregations
|
318
317
|
include Transactions
|
319
318
|
include TouchLater
|
320
319
|
include NoTouching
|
@@ -75,21 +75,7 @@ module ActiveRecord
|
|
75
75
|
# end
|
76
76
|
#
|
77
77
|
# Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
|
78
|
-
# run, both +destroy_author+ and +destroy_readers+ are called.
|
79
|
-
# where the +before_destroy+ method is overridden:
|
80
|
-
#
|
81
|
-
# class Topic < ActiveRecord::Base
|
82
|
-
# def before_destroy() destroy_author end
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# class Reply < Topic
|
86
|
-
# def before_destroy() destroy_readers end
|
87
|
-
# end
|
88
|
-
#
|
89
|
-
# In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
|
90
|
-
# So, use the callback macros when you want to ensure that a certain callback is called for the entire
|
91
|
-
# hierarchy, and use the regular overwritable methods when you want to leave it up to each descendant
|
92
|
-
# to decide whether they want to call +super+ and trigger the inherited callbacks.
|
78
|
+
# run, both +destroy_author+ and +destroy_readers+ are called.
|
93
79
|
#
|
94
80
|
# *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
|
95
81
|
# callbacks before specifying the associations. Otherwise, you might trigger the loading of a
|
@@ -109,7 +95,7 @@ module ActiveRecord
|
|
109
95
|
#
|
110
96
|
# private
|
111
97
|
# def delete_parents
|
112
|
-
# self.class.
|
98
|
+
# self.class.delete_by(parent_id: id)
|
113
99
|
# end
|
114
100
|
# end
|
115
101
|
#
|
@@ -142,7 +128,7 @@ module ActiveRecord
|
|
142
128
|
# end
|
143
129
|
# end
|
144
130
|
#
|
145
|
-
# So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
|
131
|
+
# So you specify the object you want to be messaged on a given callback. When that callback is triggered, the object has
|
146
132
|
# a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
|
147
133
|
# initialization data such as the name of the attribute to work with:
|
148
134
|
#
|
@@ -338,7 +324,7 @@ module ActiveRecord
|
|
338
324
|
|
339
325
|
private
|
340
326
|
|
341
|
-
def create_or_update(
|
327
|
+
def create_or_update(**)
|
342
328
|
_run_save_callbacks { super }
|
343
329
|
end
|
344
330
|
|
@@ -346,7 +332,7 @@ module ActiveRecord
|
|
346
332
|
_run_create_callbacks { super }
|
347
333
|
end
|
348
334
|
|
349
|
-
def _update_record
|
335
|
+
def _update_record
|
350
336
|
_run_update_callbacks { super }
|
351
337
|
end
|
352
338
|
end
|