activerecord 6.0.6 → 6.1.0
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 +783 -910
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +22 -14
- data/lib/active_record/associations/alias_tracker.rb +19 -15
- data/lib/active_record/associations/association.rb +43 -26
- data/lib/active_record/associations/association_scope.rb +11 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +19 -13
- data/lib/active_record/associations/collection_proxy.rb +12 -5
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -2
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +63 -49
- data/lib/active_record/associations/preloader/association.rb +13 -5
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +5 -3
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations.rb +114 -11
- data/lib/active_record/attribute_assignment.rb +10 -8
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
- data/lib/active_record/attribute_methods/dirty.rb +1 -11
- data/lib/active_record/attribute_methods/primary_key.rb +6 -2
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -11
- data/lib/active_record/attribute_methods/serialization.rb +11 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
- data/lib/active_record/attribute_methods/write.rb +12 -20
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -7
- data/lib/active_record/autosave_association.rb +47 -30
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +152 -22
- data/lib/active_record/coders/yaml_column.rb +2 -24
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
- data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
- data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -71
- data/lib/active_record/core.rb +223 -66
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -40
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/enum.rb +27 -10
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -4
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -2
- data/lib/active_record/fixtures.rb +54 -8
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -18
- data/lib/active_record/insert_all.rb +34 -5
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +13 -16
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +26 -8
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
- data/lib/active_record/middleware/database_selector.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +47 -27
- data/lib/active_record/migration/compatibility.rb +67 -17
- data/lib/active_record/migration.rb +113 -83
- data/lib/active_record/model_schema.rb +88 -13
- data/lib/active_record/nested_attributes.rb +2 -3
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +50 -45
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +11 -6
- data/lib/active_record/railtie.rb +64 -44
- data/lib/active_record/railties/databases.rake +266 -95
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -31
- data/lib/active_record/relation/calculations.rb +100 -43
- data/lib/active_record/relation/finder_methods.rb +44 -14
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +20 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +57 -33
- data/lib/active_record/relation/query_methods.rb +318 -195
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +104 -57
- data/lib/active_record/relation.rb +90 -64
- data/lib/active_record/result.rb +41 -33
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/named.rb +1 -17
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -51
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +36 -33
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/touch_later.rb +21 -21
- data/lib/active_record/transactions.rb +15 -64
- data/lib/active_record/type/serialized.rb +6 -2
- data/lib/active_record/type.rb +8 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +7 -14
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +12 -18
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -2
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -4
- data/lib/arel/visitors/to_sql.rb +89 -78
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -13
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
- data/lib/rails/generators/active_record/migration.rb +6 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +28 -30
- data/lib/active_record/advisory_lock_base.rb +0 -18
- data/lib/active_record/attribute_decorators.rb +0 -88
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -203
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -156
- data/lib/arel/visitors/oracle.rb +0 -158
- data/lib/arel/visitors/oracle12.rb +0 -65
- data/lib/arel/visitors/where_sql.rb +0 -22
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -132,7 +132,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
132
132
|
SQLite3[link:classes/ActiveRecord/ConnectionAdapters/SQLite3Adapter.html].
|
133
133
|
|
134
134
|
|
135
|
-
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[
|
135
|
+
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[https://ruby-doc.org/stdlib/libdoc/logger/rdoc/].
|
136
136
|
|
137
137
|
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
138
138
|
ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
|
@@ -140,7 +140,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
140
140
|
|
141
141
|
* Database agnostic schema management with Migrations.
|
142
142
|
|
143
|
-
class AddSystemSettings < ActiveRecord::Migration[
|
143
|
+
class AddSystemSettings < ActiveRecord::Migration[6.0]
|
144
144
|
def up
|
145
145
|
create_table :system_settings do |t|
|
146
146
|
t.string :name
|
@@ -194,7 +194,7 @@ The latest version of Active Record can be installed with RubyGems:
|
|
194
194
|
|
195
195
|
Source code can be downloaded as part of the Rails project on GitHub:
|
196
196
|
|
197
|
-
* https://github.com/rails/rails/tree/
|
197
|
+
* https://github.com/rails/rails/tree/master/activerecord
|
198
198
|
|
199
199
|
|
200
200
|
== License
|
@@ -141,7 +141,7 @@ module ActiveRecord
|
|
141
141
|
# converted to an instance of value class if necessary.
|
142
142
|
#
|
143
143
|
# For example, the +NetworkResource+ model has +network_address+ and +cidr_range+ attributes that should be
|
144
|
-
# aggregated using the +NetAddr::CIDR+ value class (
|
144
|
+
# aggregated using the +NetAddr::CIDR+ value class (https://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR).
|
145
145
|
# The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter.
|
146
146
|
# New values can be assigned to the value object using either another +NetAddr::CIDR+ object, a string
|
147
147
|
# or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
class AssociationRelation < Relation
|
4
|
+
class AssociationRelation < Relation # :nodoc:
|
5
5
|
def initialize(klass, association, **)
|
6
6
|
super(klass)
|
7
7
|
@association = association
|
@@ -15,23 +15,31 @@ module ActiveRecord
|
|
15
15
|
other == records
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
def create(attributes = nil, &block)
|
25
|
-
block = _deprecated_scope_block("create", &block)
|
26
|
-
scoping { @association.create(attributes, &block) }
|
27
|
-
end
|
18
|
+
%w(insert insert_all insert! insert_all! upsert upsert_all).each do |method|
|
19
|
+
class_eval <<~RUBY
|
20
|
+
def #{method}(attributes, **kwargs)
|
21
|
+
if @association.reflection.through_reflection?
|
22
|
+
raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
|
23
|
+
end
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
scoping { klass.#{method}(attributes, **kwargs) }
|
26
|
+
end
|
27
|
+
RUBY
|
32
28
|
end
|
33
29
|
|
34
30
|
private
|
31
|
+
def _new(attributes, &block)
|
32
|
+
@association.build(attributes, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def _create(attributes, &block)
|
36
|
+
@association.create(attributes, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def _create!(attributes, &block)
|
40
|
+
@association.create!(attributes, &block)
|
41
|
+
end
|
42
|
+
|
35
43
|
def exec_queries
|
36
44
|
super do |record|
|
37
45
|
@association.set_inverse_instance_from_queries(record)
|
@@ -6,9 +6,14 @@ module ActiveRecord
|
|
6
6
|
module Associations
|
7
7
|
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
|
8
8
|
class AliasTracker # :nodoc:
|
9
|
-
def self.create(connection, initial_table, joins)
|
9
|
+
def self.create(connection, initial_table, joins, aliases = nil)
|
10
10
|
if joins.empty?
|
11
|
-
aliases
|
11
|
+
aliases ||= Hash.new(0)
|
12
|
+
elsif aliases
|
13
|
+
default_proc = aliases.default_proc || proc { 0 }
|
14
|
+
aliases.default_proc = proc { |h, k|
|
15
|
+
h[k] = initial_count_for(connection, k, joins) + default_proc.call(h, k)
|
16
|
+
}
|
12
17
|
else
|
13
18
|
aliases = Hash.new { |h, k|
|
14
19
|
h[k] = initial_count_for(connection, k, joins)
|
@@ -32,8 +37,6 @@ module ActiveRecord
|
|
32
37
|
).size
|
33
38
|
elsif join.is_a?(Arel::Nodes::Join)
|
34
39
|
join.left.name == name ? 1 : 0
|
35
|
-
elsif join.is_a?(Hash)
|
36
|
-
join[name]
|
37
40
|
else
|
38
41
|
raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
|
39
42
|
end
|
@@ -48,25 +51,26 @@ module ActiveRecord
|
|
48
51
|
@connection = connection
|
49
52
|
end
|
50
53
|
|
51
|
-
def aliased_table_for(
|
52
|
-
|
54
|
+
def aliased_table_for(arel_table, table_name = nil)
|
55
|
+
table_name ||= arel_table.name
|
56
|
+
|
57
|
+
if aliases[table_name] == 0
|
53
58
|
# If it's zero, we can have our table_name
|
54
59
|
aliases[table_name] = 1
|
55
|
-
|
60
|
+
arel_table = arel_table.alias(table_name) if arel_table.name != table_name
|
56
61
|
else
|
57
62
|
# Otherwise, we need to use an alias
|
58
|
-
aliased_name = @connection.table_alias_for(
|
63
|
+
aliased_name = @connection.table_alias_for(yield)
|
59
64
|
|
60
65
|
# Update the count
|
61
|
-
aliases[aliased_name] += 1
|
66
|
+
count = aliases[aliased_name] += 1
|
62
67
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
aliased_name
|
67
|
-
end
|
68
|
-
Arel::Table.new(table_name, type_caster: type_caster).alias(table_alias)
|
68
|
+
aliased_name = "#{truncate(aliased_name)}_#{count}" if count > 1
|
69
|
+
|
70
|
+
arel_table = arel_table.alias(aliased_name)
|
69
71
|
end
|
72
|
+
|
73
|
+
arel_table
|
70
74
|
end
|
71
75
|
|
72
76
|
attr_reader :aliases
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/array/wrap"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
module Associations
|
7
5
|
# = Active Record Associations
|
@@ -56,6 +54,10 @@ module ActiveRecord
|
|
56
54
|
@inversed = false
|
57
55
|
end
|
58
56
|
|
57
|
+
def reset_negative_cache # :nodoc:
|
58
|
+
reset if loaded? && target.nil?
|
59
|
+
end
|
60
|
+
|
59
61
|
# Reloads the \target and returns +self+ on success.
|
60
62
|
# The QueryCache is cleared if +force+ is true.
|
61
63
|
def reload(force = false)
|
@@ -132,7 +134,15 @@ module ActiveRecord
|
|
132
134
|
self.target = record
|
133
135
|
@inversed = !!record
|
134
136
|
end
|
135
|
-
|
137
|
+
|
138
|
+
def inversed_from_queries(record)
|
139
|
+
if inversable?(record)
|
140
|
+
self.target = record
|
141
|
+
@inversed = true
|
142
|
+
else
|
143
|
+
@inversed = false
|
144
|
+
end
|
145
|
+
end
|
136
146
|
|
137
147
|
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
|
138
148
|
# polymorphic_type field on the owner.
|
@@ -191,16 +201,24 @@ module ActiveRecord
|
|
191
201
|
set_inverse_instance(record)
|
192
202
|
end
|
193
203
|
|
194
|
-
def create(attributes =
|
204
|
+
def create(attributes = nil, &block)
|
195
205
|
_create_record(attributes, &block)
|
196
206
|
end
|
197
207
|
|
198
|
-
def create!(attributes =
|
208
|
+
def create!(attributes = nil, &block)
|
199
209
|
_create_record(attributes, true, &block)
|
200
210
|
end
|
201
211
|
|
202
212
|
private
|
203
213
|
def find_target
|
214
|
+
if owner.strict_loading? && owner.validation_context.nil?
|
215
|
+
Base.strict_loading_violation!(owner: owner.class, association: klass)
|
216
|
+
end
|
217
|
+
|
218
|
+
if reflection.strict_loading? && owner.validation_context.nil?
|
219
|
+
Base.strict_loading_violation!(owner: owner.class, association: reflection.name)
|
220
|
+
end
|
221
|
+
|
204
222
|
scope = self.scope
|
205
223
|
return scope.to_a if skip_statement_cache?(scope)
|
206
224
|
|
@@ -210,7 +228,7 @@ module ActiveRecord
|
|
210
228
|
end
|
211
229
|
|
212
230
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
213
|
-
sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
|
231
|
+
sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) }
|
214
232
|
end
|
215
233
|
|
216
234
|
# The scope for this association.
|
@@ -239,25 +257,6 @@ module ActiveRecord
|
|
239
257
|
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
|
240
258
|
end
|
241
259
|
|
242
|
-
def creation_attributes
|
243
|
-
attributes = {}
|
244
|
-
|
245
|
-
if (reflection.has_one? || reflection.collection?) && !options[:through]
|
246
|
-
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
|
247
|
-
|
248
|
-
if reflection.type
|
249
|
-
attributes[reflection.type] = owner.class.polymorphic_name
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
attributes
|
254
|
-
end
|
255
|
-
|
256
|
-
# Sets the owner attributes on the given record
|
257
|
-
def set_owner_attributes(record)
|
258
|
-
creation_attributes.each { |key, value| record[key] = value }
|
259
|
-
end
|
260
|
-
|
261
260
|
# Returns true if there is a foreign key present on the owner which
|
262
261
|
# references the target. This is used to determine whether we can load
|
263
262
|
# the target if the owner is currently a new record (and therefore
|
@@ -305,7 +304,7 @@ module ActiveRecord
|
|
305
304
|
|
306
305
|
# Returns true if record contains the foreign_key
|
307
306
|
def foreign_key_for?(record)
|
308
|
-
record.
|
307
|
+
record._has_attribute?(reflection.foreign_key)
|
309
308
|
end
|
310
309
|
|
311
310
|
# This should be implemented to return the values of the relevant key(s) on the owner,
|
@@ -330,6 +329,24 @@ module ActiveRecord
|
|
330
329
|
klass.scope_attributes? ||
|
331
330
|
reflection.source_reflection.active_record.default_scopes.any?
|
332
331
|
end
|
332
|
+
|
333
|
+
def enqueue_destroy_association(options)
|
334
|
+
owner.class.destroy_association_async_job&.perform_later(**options)
|
335
|
+
end
|
336
|
+
|
337
|
+
def inversable?(record)
|
338
|
+
record &&
|
339
|
+
((!record.persisted? || !owner.persisted?) || matches_foreign_key?(record))
|
340
|
+
end
|
341
|
+
|
342
|
+
def matches_foreign_key?(record)
|
343
|
+
if foreign_key_for?(record)
|
344
|
+
record.read_attribute(reflection.foreign_key) == owner.id ||
|
345
|
+
(foreign_key_for?(owner) && owner.read_attribute(reflection.foreign_key) == record.id)
|
346
|
+
else
|
347
|
+
owner.read_attribute(reflection.foreign_key) == record.id
|
348
|
+
end
|
349
|
+
end
|
333
350
|
end
|
334
351
|
end
|
335
352
|
end
|
@@ -52,17 +52,16 @@ module ActiveRecord
|
|
52
52
|
attr_reader :value_transformation
|
53
53
|
|
54
54
|
def join(table, constraint)
|
55
|
-
|
55
|
+
Arel::Nodes::LeadingJoin.new(table, Arel::Nodes::On.new(constraint))
|
56
56
|
end
|
57
57
|
|
58
58
|
def last_chain_scope(scope, reflection, owner)
|
59
|
-
|
60
|
-
|
61
|
-
foreign_key = join_keys.foreign_key
|
59
|
+
primary_key = reflection.join_primary_key
|
60
|
+
foreign_key = reflection.join_foreign_key
|
62
61
|
|
63
62
|
table = reflection.aliased_table
|
64
63
|
value = transform_value(owner[foreign_key])
|
65
|
-
scope = apply_scope(scope, table,
|
64
|
+
scope = apply_scope(scope, table, primary_key, value)
|
66
65
|
|
67
66
|
if reflection.type
|
68
67
|
polymorphic_type = transform_value(owner.class.polymorphic_name)
|
@@ -77,13 +76,12 @@ module ActiveRecord
|
|
77
76
|
end
|
78
77
|
|
79
78
|
def next_chain_scope(scope, reflection, next_reflection)
|
80
|
-
|
81
|
-
|
82
|
-
foreign_key = join_keys.foreign_key
|
79
|
+
primary_key = reflection.join_primary_key
|
80
|
+
foreign_key = reflection.join_foreign_key
|
83
81
|
|
84
82
|
table = reflection.aliased_table
|
85
83
|
foreign_table = next_reflection.aliased_table
|
86
|
-
constraint = table[
|
84
|
+
constraint = table[primary_key].eq(foreign_table[foreign_key])
|
87
85
|
|
88
86
|
if reflection.type
|
89
87
|
value = transform_value(next_reflection.klass.polymorphic_name)
|
@@ -108,11 +106,9 @@ module ActiveRecord
|
|
108
106
|
name = reflection.name
|
109
107
|
chain = [Reflection::RuntimeReflection.new(reflection, association)]
|
110
108
|
reflection.chain.drop(1).each do |refl|
|
111
|
-
aliased_table = tracker.aliased_table_for(
|
112
|
-
refl.
|
113
|
-
|
114
|
-
refl.klass.type_caster
|
115
|
-
)
|
109
|
+
aliased_table = tracker.aliased_table_for(refl.klass.arel_table) do
|
110
|
+
refl.alias_candidate(name)
|
111
|
+
end
|
116
112
|
chain << ReflectionProxy.new(refl, aliased_table)
|
117
113
|
end
|
118
114
|
chain
|
@@ -143,7 +139,7 @@ module ActiveRecord
|
|
143
139
|
end
|
144
140
|
|
145
141
|
reflection.all_includes do
|
146
|
-
scope.
|
142
|
+
scope.includes_values |= item.includes_values
|
147
143
|
end
|
148
144
|
|
149
145
|
scope.unscope!(*item.unscope_values)
|
@@ -11,8 +11,20 @@ module ActiveRecord
|
|
11
11
|
when :destroy
|
12
12
|
target.destroy
|
13
13
|
raise ActiveRecord::Rollback unless target.destroyed?
|
14
|
+
when :destroy_async
|
15
|
+
id = owner.public_send(reflection.foreign_key.to_sym)
|
16
|
+
primary_key_column = reflection.active_record_primary_key.to_sym
|
17
|
+
|
18
|
+
enqueue_destroy_association(
|
19
|
+
owner_model_name: owner.class.to_s,
|
20
|
+
owner_id: owner.id,
|
21
|
+
association_class: reflection.klass.to_s,
|
22
|
+
association_ids: [id],
|
23
|
+
association_primary_key_column: primary_key_column,
|
24
|
+
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
25
|
+
)
|
14
26
|
else
|
15
|
-
target.
|
27
|
+
target.public_send(options[:dependent])
|
16
28
|
end
|
17
29
|
end
|
18
30
|
|
@@ -44,7 +56,7 @@ module ActiveRecord
|
|
44
56
|
|
45
57
|
def decrement_counters_before_last_save
|
46
58
|
if reflection.polymorphic?
|
47
|
-
model_was = owner.attribute_before_last_save(reflection.foreign_type)
|
59
|
+
model_was = owner.attribute_before_last_save(reflection.foreign_type)&.constantize
|
48
60
|
else
|
49
61
|
model_was = klass
|
50
62
|
end
|
@@ -108,11 +120,9 @@ module ActiveRecord
|
|
108
120
|
owner._read_attribute(reflection.foreign_key)
|
109
121
|
end
|
110
122
|
|
111
|
-
# NOTE - for now, we're only supporting inverse setting from belongs_to back onto
|
112
|
-
# has_one associations.
|
113
123
|
def invertible_for?(record)
|
114
124
|
inverse = inverse_reflection_for(record)
|
115
|
-
inverse && inverse.has_one?
|
125
|
+
inverse && (inverse.has_one? || ActiveRecord::Base.has_many_inversing)
|
116
126
|
end
|
117
127
|
|
118
128
|
def stale_state
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
|
7
7
|
def klass
|
8
8
|
type = owner[reflection.foreign_type]
|
9
|
-
type.presence && type
|
9
|
+
type.presence && owner.class.polymorphic_class_for(type)
|
10
10
|
end
|
11
11
|
|
12
12
|
def target_changed?
|
@@ -18,7 +18,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
18
18
|
end
|
19
19
|
self.extensions = []
|
20
20
|
|
21
|
-
VALID_OPTIONS = [
|
21
|
+
VALID_OPTIONS = [
|
22
|
+
:class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading
|
23
|
+
].freeze # :nodoc:
|
22
24
|
|
23
25
|
def self.build(model, name, scope, options, &block)
|
24
26
|
if model.dangerous_attribute_method?(name)
|
@@ -72,7 +74,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
72
74
|
|
73
75
|
def self.define_callbacks(model, reflection)
|
74
76
|
if dependent = reflection.options[:dependent]
|
75
|
-
check_dependent_options(dependent)
|
77
|
+
check_dependent_options(dependent, model)
|
76
78
|
add_destroy_callbacks(model, reflection)
|
77
79
|
end
|
78
80
|
|
@@ -118,7 +120,11 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
118
120
|
raise NotImplementedError
|
119
121
|
end
|
120
122
|
|
121
|
-
def self.check_dependent_options(dependent)
|
123
|
+
def self.check_dependent_options(dependent, model)
|
124
|
+
if dependent == :destroy_async && !model.destroy_association_async_job
|
125
|
+
err_message = "ActiveJob is required to use destroy_async on associations"
|
126
|
+
raise ActiveRecord::ActiveJobRequiredError, err_message
|
127
|
+
end
|
122
128
|
unless valid_dependent_options.include? dependent
|
123
129
|
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
|
124
130
|
end
|
@@ -7,11 +7,14 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
10
|
+
valid = super + [:counter_cache, :optional, :default]
|
11
|
+
valid += [:polymorphic, :foreign_type] if options[:polymorphic]
|
12
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
13
|
+
valid
|
11
14
|
end
|
12
15
|
|
13
16
|
def self.valid_dependent_options
|
14
|
-
[:destroy, :delete]
|
17
|
+
[:destroy, :delete, :destroy_async]
|
15
18
|
end
|
16
19
|
|
17
20
|
def self.define_callbacks(model, reflection)
|
@@ -55,19 +58,19 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
55
58
|
|
56
59
|
if old_record
|
57
60
|
if touch != true
|
58
|
-
old_record.
|
61
|
+
old_record.public_send(touch_method, touch)
|
59
62
|
else
|
60
|
-
old_record.
|
63
|
+
old_record.public_send(touch_method)
|
61
64
|
end
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
65
|
-
record = o.
|
68
|
+
record = o.public_send name
|
66
69
|
if record && record.persisted?
|
67
70
|
if touch != true
|
68
|
-
record.
|
71
|
+
record.public_send(touch_method, touch)
|
69
72
|
else
|
70
|
-
record.
|
73
|
+
record.public_send(touch_method)
|
71
74
|
end
|
72
75
|
end
|
73
76
|
end
|
@@ -7,8 +7,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
11
|
-
:after_add, :before_remove, :after_remove, :extend]
|
10
|
+
super + [:before_add, :after_add, :before_remove, :after_remove, :extend]
|
12
11
|
end
|
13
12
|
|
14
13
|
def self.define_callbacks(model, reflection)
|
@@ -31,8 +30,10 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
31
30
|
def self.define_callback(model, callback_name, name, options)
|
32
31
|
full_callback_name = "#{callback_name}_for_#{name}"
|
33
32
|
|
34
|
-
|
35
|
-
|
33
|
+
unless model.method_defined?(full_callback_name)
|
34
|
+
model.class_attribute(full_callback_name, instance_accessor: false, instance_predicate: false)
|
35
|
+
end
|
36
|
+
|
36
37
|
callbacks = Array(options[callback_name.to_sym]).map do |callback|
|
37
38
|
case callback
|
38
39
|
when Symbol
|
@@ -75,7 +75,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
75
75
|
def middle_options(join_model)
|
76
76
|
middle_options = {}
|
77
77
|
middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
|
78
|
-
middle_options[:source] = join_model.left_reflection.name
|
79
78
|
if options.key? :foreign_key
|
80
79
|
middle_options[:foreign_key] = options[:foreign_key]
|
81
80
|
end
|
@@ -7,11 +7,15 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
10
|
+
valid = super + [:counter_cache, :join_table, :index_errors, :ensuring_owner_was]
|
11
|
+
valid += [:as, :foreign_type] if options[:as]
|
12
|
+
valid += [:through, :source, :source_type] if options[:through]
|
13
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
14
|
+
valid
|
11
15
|
end
|
12
16
|
|
13
17
|
def self.valid_dependent_options
|
14
|
-
[:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception]
|
18
|
+
[:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception, :destroy_async]
|
15
19
|
end
|
16
20
|
|
17
21
|
private_class_method :macro, :valid_options, :valid_dependent_options
|
@@ -7,13 +7,15 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
valid = super
|
10
|
+
valid = super
|
11
|
+
valid += [:as, :foreign_type] if options[:as]
|
12
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
11
13
|
valid += [:through, :source, :source_type] if options[:through]
|
12
14
|
valid
|
13
15
|
end
|
14
16
|
|
15
17
|
def self.valid_dependent_options
|
16
|
-
[:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
|
18
|
+
[:destroy, :destroy_async, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
|
17
19
|
end
|
18
20
|
|
19
21
|
def self.define_callbacks(model, reflection)
|
@@ -32,15 +34,12 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
def self.touch_record(
|
36
|
-
|
37
|
+
def self.touch_record(record, name, touch)
|
38
|
+
instance = record.send(name)
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
record.touch(touch)
|
42
|
-
else
|
43
|
-
record.touch
|
40
|
+
if instance&.persisted?
|
41
|
+
touch != true ?
|
42
|
+
instance.touch(touch) : instance.touch
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
@@ -48,11 +47,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
48
47
|
name = reflection.name
|
49
48
|
touch = reflection.options[:touch]
|
50
49
|
|
51
|
-
callback =
|
52
|
-
HasOne.touch_record(record, name, touch)
|
53
|
-
}
|
54
|
-
|
50
|
+
callback = -> (record) { HasOne.touch_record(record, name, touch) }
|
55
51
|
model.after_create callback, if: :saved_changes?
|
52
|
+
model.after_create_commit { association(name).reset_negative_cache }
|
56
53
|
model.after_update callback, if: :saved_changes?
|
57
54
|
model.after_destroy callback
|
58
55
|
model.after_touch callback
|
@@ -5,7 +5,7 @@
|
|
5
5
|
module ActiveRecord::Associations::Builder # :nodoc:
|
6
6
|
class SingularAssociation < Association #:nodoc:
|
7
7
|
def self.valid_options(options)
|
8
|
-
super + [:
|
8
|
+
super + [:required, :touch]
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.define_accessors(model, reflection)
|