activerecord 5.2.1.1 → 6.0.1
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 +738 -445
- 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 +18 -9
- data/lib/active_record/associations.rb +20 -15
- data/lib/active_record/associations/association.rb +69 -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 +15 -29
- 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 +11 -10
- data/lib/active_record/associations/has_many_through_association.rb +42 -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 +39 -31
- 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 +114 -38
- 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 +27 -13
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -20
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +140 -27
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +22 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +116 -127
- 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 +55 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +9 -4
- 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 +8 -2
- 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 +65 -77
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +172 -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 +38 -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 +34 -10
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +233 -28
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- data/lib/active_record/railtie.rb +81 -46
- 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 +196 -46
- data/lib/active_record/reflection.rb +42 -44
- data/lib/active_record/relation.rb +320 -70
- 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 +48 -35
- data/lib/active_record/relation/finder_methods.rb +30 -30
- data/lib/active_record/relation/merger.rb +19 -25
- data/lib/active_record/relation/predicate_builder.rb +18 -15
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -6
- 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 +236 -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 +21 -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 +195 -26
- 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 +224 -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 -27
- data/lib/active_record/collection_cache_key.rb +0 -53
data/MIT-LICENSE
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
Copyright (c) 2004-
|
1
|
+
Copyright (c) 2004-2019 David Heinemeier Hansson
|
2
|
+
|
3
|
+
Arel originally copyright (c) 2007-2016 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
|
2
4
|
|
3
5
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
6
|
a copy of this software and associated documentation files (the
|
data/README.rdoc
CHANGED
@@ -13,6 +13,8 @@ columns. Although these mappings can be defined explicitly, it's recommended
|
|
13
13
|
to follow naming conventions, especially when getting started with the
|
14
14
|
library.
|
15
15
|
|
16
|
+
You can read more about Active Record in the {Active Record Basics}[https://edgeguides.rubyonrails.org/active_record_basics.html] guide.
|
17
|
+
|
16
18
|
A short rundown of some of the major features:
|
17
19
|
|
18
20
|
* Automated mapping between classes and tables, attributes and columns.
|
@@ -192,7 +194,7 @@ The latest version of Active Record can be installed with RubyGems:
|
|
192
194
|
|
193
195
|
Source code can be downloaded as part of the Rails project on GitHub:
|
194
196
|
|
195
|
-
* https://github.com/rails/rails/tree/
|
197
|
+
* https://github.com/rails/rails/tree/master/activerecord
|
196
198
|
|
197
199
|
|
198
200
|
== License
|
@@ -206,7 +208,7 @@ Active Record is released under the MIT license:
|
|
206
208
|
|
207
209
|
API documentation is at:
|
208
210
|
|
209
|
-
*
|
211
|
+
* https://api.rubyonrails.org
|
210
212
|
|
211
213
|
Bug reports for the Ruby on Rails project can be filed here:
|
212
214
|
|
data/examples/performance.rb
CHANGED
data/lib/active_record.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2019 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
@@ -55,7 +55,6 @@ module ActiveRecord
|
|
55
55
|
autoload :Persistence
|
56
56
|
autoload :QueryCache
|
57
57
|
autoload :Querying
|
58
|
-
autoload :CollectionCacheKey
|
59
58
|
autoload :ReadonlyAttributes
|
60
59
|
autoload :RecordInvalid, "active_record/validations"
|
61
60
|
autoload :Reflection
|
@@ -74,6 +73,7 @@ module ActiveRecord
|
|
74
73
|
autoload :Translation
|
75
74
|
autoload :Validations
|
76
75
|
autoload :SecureToken
|
76
|
+
autoload :DatabaseSelector, "active_record/middleware/database_selector"
|
77
77
|
|
78
78
|
eager_autoload do
|
79
79
|
autoload :ActiveRecordError, "active_record/errors"
|
@@ -153,6 +153,12 @@ module ActiveRecord
|
|
153
153
|
end
|
154
154
|
end
|
155
155
|
|
156
|
+
module Middleware
|
157
|
+
extend ActiveSupport::Autoload
|
158
|
+
|
159
|
+
autoload :DatabaseSelector, "active_record/middleware/database_selector"
|
160
|
+
end
|
161
|
+
|
156
162
|
module Tasks
|
157
163
|
extend ActiveSupport::Autoload
|
158
164
|
|
@@ -163,6 +169,7 @@ module ActiveRecord
|
|
163
169
|
"active_record/tasks/postgresql_database_tasks"
|
164
170
|
end
|
165
171
|
|
172
|
+
autoload :TestDatabases, "active_record/test_databases"
|
166
173
|
autoload :TestFixtures, "active_record/fixtures"
|
167
174
|
|
168
175
|
def self.eager_load!
|
@@ -3,8 +3,6 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
# See ActiveRecord::Aggregations::ClassMethods for documentation
|
5
5
|
module Aggregations
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
6
|
def initialize_dup(*) # :nodoc:
|
9
7
|
@aggregation_cache = {}
|
10
8
|
super
|
@@ -225,6 +223,10 @@ module ActiveRecord
|
|
225
223
|
def composed_of(part_id, options = {})
|
226
224
|
options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
|
227
225
|
|
226
|
+
unless self < Aggregations
|
227
|
+
include Aggregations
|
228
|
+
end
|
229
|
+
|
228
230
|
name = part_id.id2name
|
229
231
|
class_name = options[:class_name] || name.camelize
|
230
232
|
mapping = options[:mapping] || [ name, name ]
|
@@ -15,25 +15,34 @@ module ActiveRecord
|
|
15
15
|
other == records
|
16
16
|
end
|
17
17
|
|
18
|
-
def build(
|
19
|
-
|
18
|
+
def build(attributes = nil, &block)
|
19
|
+
block = _deprecated_scope_block("new", &block)
|
20
|
+
@association.scoping(self) do
|
21
|
+
@association.build(attributes, &block)
|
22
|
+
end
|
20
23
|
end
|
21
24
|
alias new build
|
22
25
|
|
23
|
-
def create(
|
24
|
-
|
26
|
+
def create(attributes = nil, &block)
|
27
|
+
block = _deprecated_scope_block("create", &block)
|
28
|
+
@association.scoping(self) do
|
29
|
+
@association.create(attributes, &block)
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
|
-
def create!(
|
28
|
-
|
33
|
+
def create!(attributes = nil, &block)
|
34
|
+
block = _deprecated_scope_block("create!", &block)
|
35
|
+
@association.scoping(self) do
|
36
|
+
@association.create!(attributes, &block)
|
37
|
+
end
|
29
38
|
end
|
30
39
|
|
31
40
|
private
|
32
41
|
|
33
42
|
def exec_queries
|
34
|
-
super do |
|
35
|
-
@association.
|
36
|
-
yield
|
43
|
+
super do |record|
|
44
|
+
@association.set_inverse_instance_from_queries(record)
|
45
|
+
yield record if block_given?
|
37
46
|
end
|
38
47
|
end
|
39
48
|
end
|
@@ -92,7 +92,7 @@ module ActiveRecord
|
|
92
92
|
through_reflection = reflection.through_reflection
|
93
93
|
source_reflection_names = reflection.source_reflection_names
|
94
94
|
source_associations = reflection.through_reflection.klass._reflections.keys
|
95
|
-
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or '
|
95
|
+
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')}?")
|
96
96
|
else
|
97
97
|
super("Could not find the source association(s).")
|
98
98
|
end
|
@@ -292,13 +292,13 @@ module ActiveRecord
|
|
292
292
|
#
|
293
293
|
# The project class now has the following methods (and more) to ease the traversal and
|
294
294
|
# manipulation of its relationships:
|
295
|
-
# * <tt>Project#portfolio
|
296
|
-
# * <tt>Project#project_manager
|
297
|
-
# * <tt>Project#milestones.empty
|
298
|
-
# <tt>Project#milestones.delete(milestone)
|
299
|
-
# <tt>Project#milestones.build
|
300
|
-
# * <tt>Project#categories.empty
|
301
|
-
# <tt>Project#categories.delete(category1)
|
295
|
+
# * <tt>Project#portfolio</tt>, <tt>Project#portfolio=(portfolio)</tt>, <tt>Project#reload_portfolio</tt>
|
296
|
+
# * <tt>Project#project_manager</tt>, <tt>Project#project_manager=(project_manager)</tt>, <tt>Project#reload_project_manager</tt>
|
297
|
+
# * <tt>Project#milestones.empty?</tt>, <tt>Project#milestones.size</tt>, <tt>Project#milestones</tt>, <tt>Project#milestones<<(milestone)</tt>,
|
298
|
+
# <tt>Project#milestones.delete(milestone)</tt>, <tt>Project#milestones.destroy(milestone)</tt>, <tt>Project#milestones.find(milestone_id)</tt>,
|
299
|
+
# <tt>Project#milestones.build</tt>, <tt>Project#milestones.create</tt>
|
300
|
+
# * <tt>Project#categories.empty?</tt>, <tt>Project#categories.size</tt>, <tt>Project#categories</tt>, <tt>Project#categories<<(category1)</tt>,
|
301
|
+
# <tt>Project#categories.delete(category1)</tt>, <tt>Project#categories.destroy(category1)</tt>
|
302
302
|
#
|
303
303
|
# === A word of warning
|
304
304
|
#
|
@@ -703,8 +703,9 @@ module ActiveRecord
|
|
703
703
|
# #belongs_to associations.
|
704
704
|
#
|
705
705
|
# Extra options on the associations, as defined in the
|
706
|
-
# <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt>
|
707
|
-
# also prevent the association's inverse
|
706
|
+
# <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt>
|
707
|
+
# constant, or a custom scope, will also prevent the association's inverse
|
708
|
+
# from being found automatically.
|
708
709
|
#
|
709
710
|
# The automatic guessing of the inverse association uses a heuristic based
|
710
711
|
# on the name of the class, so it may not work for all associations,
|
@@ -1293,8 +1294,9 @@ module ActiveRecord
|
|
1293
1294
|
#
|
1294
1295
|
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
|
1295
1296
|
# * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
|
1296
|
-
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+.
|
1297
|
-
#
|
1297
|
+
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Polymorphic type will also be nullified
|
1298
|
+
# on polymorphic associations. Callbacks are not executed.
|
1299
|
+
# * <tt>:restrict_with_exception</tt> causes an <tt>ActiveRecord::DeleteRestrictionError</tt> exception to be raised if there are any associated records.
|
1298
1300
|
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects.
|
1299
1301
|
#
|
1300
1302
|
# If using with the <tt>:through</tt> option, the association on the join model must be
|
@@ -1436,8 +1438,9 @@ module ActiveRecord
|
|
1436
1438
|
#
|
1437
1439
|
# * <tt>:destroy</tt> causes the associated object to also be destroyed
|
1438
1440
|
# * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
|
1439
|
-
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+.
|
1440
|
-
#
|
1441
|
+
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Polymorphic type column is also nullified
|
1442
|
+
# on polymorphic associations. Callbacks are not executed.
|
1443
|
+
# * <tt>:restrict_with_exception</tt> causes an <tt>ActiveRecord::DeleteRestrictionError</tt> exception to be raised if there is an associated record
|
1441
1444
|
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
|
1442
1445
|
#
|
1443
1446
|
# Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option.
|
@@ -1524,6 +1527,7 @@ module ActiveRecord
|
|
1524
1527
|
# Returns the associated object. +nil+ is returned if none is found.
|
1525
1528
|
# [association=(associate)]
|
1526
1529
|
# Assigns the associate object, extracts the primary key, and sets it as the foreign key.
|
1530
|
+
# No modification or deletion of existing records takes place.
|
1527
1531
|
# [build_association(attributes = {})]
|
1528
1532
|
# Returns a new object of the associated type that has been instantiated
|
1529
1533
|
# with +attributes+ and linked to this object through a foreign key, but has not yet been saved.
|
@@ -1581,7 +1585,7 @@ module ActiveRecord
|
|
1581
1585
|
# association will use "taggable_type" as the default <tt>:foreign_type</tt>.
|
1582
1586
|
# [:primary_key]
|
1583
1587
|
# Specify the method that returns the primary key of associated object used for the association.
|
1584
|
-
# By default this is id
|
1588
|
+
# By default this is +id+.
|
1585
1589
|
# [:dependent]
|
1586
1590
|
# If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
|
1587
1591
|
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
|
@@ -1761,6 +1765,7 @@ module ActiveRecord
|
|
1761
1765
|
# has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) }
|
1762
1766
|
# has_and_belongs_to_many :categories, ->(post) {
|
1763
1767
|
# where("default_category = ?", post.default_category)
|
1768
|
+
# }
|
1764
1769
|
#
|
1765
1770
|
# === Extensions
|
1766
1771
|
#
|
@@ -17,6 +17,23 @@ module ActiveRecord
|
|
17
17
|
# CollectionAssociation
|
18
18
|
# HasManyAssociation + ForeignAssociation
|
19
19
|
# HasManyThroughAssociation + ThroughAssociation
|
20
|
+
#
|
21
|
+
# Associations in Active Record are middlemen between the object that
|
22
|
+
# holds the association, known as the <tt>owner</tt>, and the associated
|
23
|
+
# result set, known as the <tt>target</tt>. Association metadata is available in
|
24
|
+
# <tt>reflection</tt>, which is an instance of <tt>ActiveRecord::Reflection::AssociationReflection</tt>.
|
25
|
+
#
|
26
|
+
# For example, given
|
27
|
+
#
|
28
|
+
# class Blog < ActiveRecord::Base
|
29
|
+
# has_many :posts
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# blog = Blog.first
|
33
|
+
#
|
34
|
+
# The association of <tt>blog.posts</tt> has the object +blog+ as its
|
35
|
+
# <tt>owner</tt>, the collection of its posts as <tt>target</tt>, and
|
36
|
+
# the <tt>reflection</tt> object represents a <tt>:has_many</tt> macro.
|
20
37
|
class Association #:nodoc:
|
21
38
|
attr_reader :owner, :target, :reflection
|
22
39
|
|
@@ -26,6 +43,7 @@ module ActiveRecord
|
|
26
43
|
reflection.check_validity!
|
27
44
|
|
28
45
|
@owner, @reflection = owner, reflection
|
46
|
+
@_scope = nil
|
29
47
|
|
30
48
|
reset
|
31
49
|
reset_scope
|
@@ -40,7 +58,9 @@ module ActiveRecord
|
|
40
58
|
end
|
41
59
|
|
42
60
|
# Reloads the \target and returns +self+ on success.
|
43
|
-
|
61
|
+
# The QueryCache is cleared if +force+ is true.
|
62
|
+
def reload(force = false)
|
63
|
+
klass.connection.clear_query_cache if force && klass
|
44
64
|
reset
|
45
65
|
reset_scope
|
46
66
|
load_target
|
@@ -76,19 +96,7 @@ module ActiveRecord
|
|
76
96
|
end
|
77
97
|
|
78
98
|
def scope
|
79
|
-
target_scope.merge!(association_scope)
|
80
|
-
end
|
81
|
-
|
82
|
-
# The scope for this association.
|
83
|
-
#
|
84
|
-
# Note that the association_scope is merged into the target_scope only when the
|
85
|
-
# scope method is called. This is because at that point the call may be surrounded
|
86
|
-
# by scope.scoping { ... } or with_scope { ... } etc, which affects the scope which
|
87
|
-
# actually gets built.
|
88
|
-
def association_scope
|
89
|
-
if klass
|
90
|
-
@association_scope ||= AssociationScope.scope(self)
|
91
|
-
end
|
99
|
+
@_scope&.spawn || target_scope.merge!(association_scope)
|
92
100
|
end
|
93
101
|
|
94
102
|
def reset_scope
|
@@ -103,6 +111,13 @@ module ActiveRecord
|
|
103
111
|
record
|
104
112
|
end
|
105
113
|
|
114
|
+
def set_inverse_instance_from_queries(record)
|
115
|
+
if inverse = inverse_association_for(record)
|
116
|
+
inverse.inversed_from_queries(owner)
|
117
|
+
end
|
118
|
+
record
|
119
|
+
end
|
120
|
+
|
106
121
|
# Remove the inverse association, if possible
|
107
122
|
def remove_inverse_instance(record)
|
108
123
|
if inverse = inverse_association_for(record)
|
@@ -114,6 +129,7 @@ module ActiveRecord
|
|
114
129
|
self.target = record
|
115
130
|
@inversed = !!record
|
116
131
|
end
|
132
|
+
alias :inversed_from_queries :inversed_from
|
117
133
|
|
118
134
|
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
|
119
135
|
# polymorphic_type field on the owner.
|
@@ -121,12 +137,6 @@ module ActiveRecord
|
|
121
137
|
reflection.klass
|
122
138
|
end
|
123
139
|
|
124
|
-
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
|
125
|
-
# through association's scope)
|
126
|
-
def target_scope
|
127
|
-
AssociationRelation.create(klass, self).merge!(klass.all)
|
128
|
-
end
|
129
|
-
|
130
140
|
def extensions
|
131
141
|
extensions = klass.default_extensions | reflection.extensions
|
132
142
|
|
@@ -186,7 +196,46 @@ module ActiveRecord
|
|
186
196
|
_create_record(attributes, true, &block)
|
187
197
|
end
|
188
198
|
|
199
|
+
def scoping(relation, &block)
|
200
|
+
@_scope = relation
|
201
|
+
relation.scoping(&block)
|
202
|
+
ensure
|
203
|
+
@_scope = nil
|
204
|
+
end
|
205
|
+
|
189
206
|
private
|
207
|
+
def find_target
|
208
|
+
scope = self.scope
|
209
|
+
return scope.to_a if skip_statement_cache?(scope)
|
210
|
+
|
211
|
+
conn = klass.connection
|
212
|
+
sc = reflection.association_scope_cache(conn, owner) do |params|
|
213
|
+
as = AssociationScope.create { params.bind }
|
214
|
+
target_scope.merge!(as.scope(self))
|
215
|
+
end
|
216
|
+
|
217
|
+
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
218
|
+
sc.execute(binds, conn) { |record| set_inverse_instance(record) } || []
|
219
|
+
end
|
220
|
+
|
221
|
+
# The scope for this association.
|
222
|
+
#
|
223
|
+
# Note that the association_scope is merged into the target_scope only when the
|
224
|
+
# scope method is called. This is because at that point the call may be surrounded
|
225
|
+
# by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
|
226
|
+
# actually gets built.
|
227
|
+
def association_scope
|
228
|
+
if klass
|
229
|
+
@association_scope ||= AssociationScope.scope(self)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
|
234
|
+
# through association's scope)
|
235
|
+
def target_scope
|
236
|
+
AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
|
237
|
+
end
|
238
|
+
|
190
239
|
def scope_for_create
|
191
240
|
scope.scope_for_create
|
192
241
|
end
|
@@ -26,7 +26,9 @@ module ActiveRecord
|
|
26
26
|
chain = get_chain(reflection, association, scope.alias_tracker)
|
27
27
|
|
28
28
|
scope.extending! reflection.extensions
|
29
|
-
add_constraints(scope, owner, chain)
|
29
|
+
scope = add_constraints(scope, owner, chain)
|
30
|
+
scope.limit!(1) unless reflection.collection?
|
31
|
+
scope
|
30
32
|
end
|
31
33
|
|
32
34
|
def self.get_bind_values(owner, chain)
|
@@ -46,13 +48,9 @@ module ActiveRecord
|
|
46
48
|
binds
|
47
49
|
end
|
48
50
|
|
49
|
-
|
50
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
51
|
-
protected
|
52
|
-
|
51
|
+
private
|
53
52
|
attr_reader :value_transformation
|
54
53
|
|
55
|
-
private
|
56
54
|
def join(table, constraint)
|
57
55
|
table.create_join(table, table.create_on(constraint))
|
58
56
|
end
|
@@ -16,21 +16,6 @@ module ActiveRecord
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def replace(record)
|
20
|
-
if record
|
21
|
-
raise_on_type_mismatch!(record)
|
22
|
-
update_counters_on_replace(record)
|
23
|
-
set_inverse_instance(record)
|
24
|
-
@updated = true
|
25
|
-
else
|
26
|
-
decrement_counters
|
27
|
-
end
|
28
|
-
|
29
|
-
replace_keys(record)
|
30
|
-
|
31
|
-
self.target = record
|
32
|
-
end
|
33
|
-
|
34
19
|
def inversed_from(record)
|
35
20
|
replace_keys(record)
|
36
21
|
super
|
@@ -49,30 +34,60 @@ module ActiveRecord
|
|
49
34
|
@updated
|
50
35
|
end
|
51
36
|
|
52
|
-
def decrement_counters
|
37
|
+
def decrement_counters
|
53
38
|
update_counters(-1)
|
54
39
|
end
|
55
40
|
|
56
|
-
def increment_counters
|
41
|
+
def increment_counters
|
57
42
|
update_counters(1)
|
58
43
|
end
|
59
44
|
|
45
|
+
def decrement_counters_before_last_save
|
46
|
+
if reflection.polymorphic?
|
47
|
+
model_was = owner.attribute_before_last_save(reflection.foreign_type).try(:constantize)
|
48
|
+
else
|
49
|
+
model_was = klass
|
50
|
+
end
|
51
|
+
|
52
|
+
foreign_key_was = owner.attribute_before_last_save(reflection.foreign_key)
|
53
|
+
|
54
|
+
if foreign_key_was && model_was < ActiveRecord::Base
|
55
|
+
update_counters_via_scope(model_was, foreign_key_was, -1)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
60
59
|
def target_changed?
|
61
60
|
owner.saved_change_to_attribute?(reflection.foreign_key)
|
62
61
|
end
|
63
62
|
|
64
63
|
private
|
64
|
+
def replace(record)
|
65
|
+
if record
|
66
|
+
raise_on_type_mismatch!(record)
|
67
|
+
set_inverse_instance(record)
|
68
|
+
@updated = true
|
69
|
+
end
|
70
|
+
|
71
|
+
replace_keys(record)
|
72
|
+
|
73
|
+
self.target = record
|
74
|
+
end
|
65
75
|
|
66
76
|
def update_counters(by)
|
67
77
|
if require_counter_update? && foreign_key_present?
|
68
78
|
if target && !stale_target?
|
69
79
|
target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch])
|
70
80
|
else
|
71
|
-
klass.
|
81
|
+
update_counters_via_scope(klass, owner._read_attribute(reflection.foreign_key), by)
|
72
82
|
end
|
73
83
|
end
|
74
84
|
end
|
75
85
|
|
86
|
+
def update_counters_via_scope(klass, foreign_key, by)
|
87
|
+
scope = klass.unscoped.where!(primary_key(klass) => foreign_key)
|
88
|
+
scope.update_counters(reflection.counter_cache_column => by, touch: reflection.options[:touch])
|
89
|
+
end
|
90
|
+
|
76
91
|
def find_target?
|
77
92
|
!loaded? && foreign_key_present? && klass
|
78
93
|
end
|
@@ -81,25 +96,12 @@ module ActiveRecord
|
|
81
96
|
reflection.counter_cache_column && owner.persisted?
|
82
97
|
end
|
83
98
|
|
84
|
-
def update_counters_on_replace(record)
|
85
|
-
if require_counter_update? && different_target?(record)
|
86
|
-
owner.instance_variable_set :@_after_replace_counter_called, true
|
87
|
-
record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
|
88
|
-
decrement_counters
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# Checks whether record is different to the current target, without loading it
|
93
|
-
def different_target?(record)
|
94
|
-
record._read_attribute(primary_key(record)) != owner._read_attribute(reflection.foreign_key)
|
95
|
-
end
|
96
|
-
|
97
99
|
def replace_keys(record)
|
98
|
-
owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil
|
100
|
+
owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record.class)) : nil
|
99
101
|
end
|
100
102
|
|
101
|
-
def primary_key(
|
102
|
-
reflection.association_primary_key(
|
103
|
+
def primary_key(klass)
|
104
|
+
reflection.association_primary_key(klass)
|
103
105
|
end
|
104
106
|
|
105
107
|
def foreign_key_present?
|
@@ -113,14 +115,6 @@ module ActiveRecord
|
|
113
115
|
inverse && inverse.has_one?
|
114
116
|
end
|
115
117
|
|
116
|
-
def target_id
|
117
|
-
if options[:primary_key]
|
118
|
-
owner.send(reflection.name).try(:id)
|
119
|
-
else
|
120
|
-
owner._read_attribute(reflection.foreign_key)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
118
|
def stale_state
|
125
119
|
result = owner._read_attribute(reflection.foreign_key) { |n| owner.send(:missing_attribute, n, caller) }
|
126
120
|
result && result.to_s
|