activerecord 5.2.6 → 6.0.5
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 +928 -559
- data/MIT-LICENSE +3 -1
- data/README.rdoc +5 -3
- data/examples/performance.rb +1 -1
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +55 -19
- data/lib/active_record/associations/association_scope.rb +11 -7
- 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 +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
- 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 +19 -23
- data/lib/active_record/associations/collection_proxy.rb +14 -17
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -11
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- 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/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
- data/lib/active_record/associations/join_dependency.rb +47 -30
- data/lib/active_record/associations/preloader/association.rb +61 -41
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +44 -33
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +21 -16
- data/lib/active_record/attribute_assignment.rb +7 -11
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -24
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -54
- data/lib/active_record/attribute_methods/serialization.rb +1 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
- data/lib/active_record/attribute_methods/write.rb +17 -25
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -1
- data/lib/active_record/autosave_association.rb +12 -14
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -21
- data/lib/active_record/coders/yaml_column.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
- 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 +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.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 +5 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
- 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 +119 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +139 -26
- data/lib/active_record/core.rb +107 -66
- data/lib/active_record/counter_cache.rb +8 -30
- 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 +78 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +44 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -2
- 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 +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +144 -474
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -6
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +11 -3
- data/lib/active_record/locking/optimistic.rb +14 -7
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +8 -27
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +54 -22
- data/lib/active_record/migration/compatibility.rb +79 -52
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +104 -85
- data/lib/active_record/model_schema.rb +62 -11
- data/lib/active_record/nested_attributes.rb +2 -4
- data/lib/active_record/no_touching.rb +9 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +232 -29
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- 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 +51 -51
- data/lib/active_record/relation/batches.rb +13 -11
- data/lib/active_record/relation/calculations.rb +55 -49
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +23 -28
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +12 -17
- 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/predicate_builder.rb +5 -11
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +232 -69
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/relation/where_clause.rb +14 -11
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +326 -81
- data/lib/active_record/result.rb +30 -12
- 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 +6 -2
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +25 -16
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +23 -15
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +39 -26
- data/lib/active_record/touch_later.rb +5 -4
- data/lib/active_record/transactions.rb +64 -73
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +0 -1
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +3 -5
- 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/associated.rb +0 -1
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +10 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -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/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/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -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/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -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/migration.rb +14 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +116 -29
- 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/main/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
|
|
@@ -214,4 +216,4 @@ Bug reports for the Ruby on Rails project can be filed here:
|
|
214
216
|
|
215
217
|
Feature requests should be discussed on the rails-core mailing list here:
|
216
218
|
|
217
|
-
* https://
|
219
|
+
* https://discuss.rubyonrails.org/c/rubyonrails-core
|
data/examples/performance.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# This class is used to create a connection that we can use for advisory
|
5
|
+
# locks. This will take out a "global" lock that can't be accidentally
|
6
|
+
# removed if a new connection is established during a migration.
|
7
|
+
class AdvisoryLockBase < ActiveRecord::Base # :nodoc:
|
8
|
+
self.abstract_class = true
|
9
|
+
|
10
|
+
self.connection_specification_name = "AdvisoryLockBase"
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def _internal?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -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
|
@@ -16,7 +14,6 @@ module ActiveRecord
|
|
16
14
|
end
|
17
15
|
|
18
16
|
private
|
19
|
-
|
20
17
|
def clear_aggregation_cache
|
21
18
|
@aggregation_cache.clear if persisted?
|
22
19
|
end
|
@@ -225,6 +222,10 @@ module ActiveRecord
|
|
225
222
|
def composed_of(part_id, options = {})
|
226
223
|
options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
|
227
224
|
|
225
|
+
unless self < Aggregations
|
226
|
+
include Aggregations
|
227
|
+
end
|
228
|
+
|
228
229
|
name = part_id.id2name
|
229
230
|
class_name = options[:class_name] || name.camelize
|
230
231
|
mapping = options[:mapping] || [ name, name ]
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class AssociationRelation < Relation
|
5
|
-
def initialize(klass, association)
|
5
|
+
def initialize(klass, association, **)
|
6
6
|
super(klass)
|
7
7
|
@association = association
|
8
8
|
end
|
@@ -15,21 +15,23 @@ 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
|
+
scoping { @association.build(attributes, &block) }
|
20
21
|
end
|
21
22
|
alias new build
|
22
23
|
|
23
|
-
def create(
|
24
|
-
|
24
|
+
def create(attributes = nil, &block)
|
25
|
+
block = _deprecated_scope_block("create", &block)
|
26
|
+
scoping { @association.create(attributes, &block) }
|
25
27
|
end
|
26
28
|
|
27
|
-
def create!(
|
28
|
-
|
29
|
+
def create!(attributes = nil, &block)
|
30
|
+
block = _deprecated_scope_block("create!", &block)
|
31
|
+
scoping { @association.create!(attributes, &block) }
|
29
32
|
end
|
30
33
|
|
31
34
|
private
|
32
|
-
|
33
35
|
def exec_queries
|
34
36
|
super do |record|
|
35
37
|
@association.set_inverse_instance_from_queries(record)
|
@@ -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
|
|
@@ -40,7 +57,9 @@ module ActiveRecord
|
|
40
57
|
end
|
41
58
|
|
42
59
|
# Reloads the \target and returns +self+ on success.
|
43
|
-
|
60
|
+
# The QueryCache is cleared if +force+ is true.
|
61
|
+
def reload(force = false)
|
62
|
+
klass.connection.clear_query_cache if force && klass
|
44
63
|
reset
|
45
64
|
reset_scope
|
46
65
|
load_target
|
@@ -76,18 +95,10 @@ module ActiveRecord
|
|
76
95
|
end
|
77
96
|
|
78
97
|
def scope
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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)
|
98
|
+
if (scope = klass.current_scope) && scope.try(:proxy_association) == self
|
99
|
+
scope.spawn
|
100
|
+
else
|
101
|
+
target_scope.merge!(association_scope)
|
91
102
|
end
|
92
103
|
end
|
93
104
|
|
@@ -129,12 +140,6 @@ module ActiveRecord
|
|
129
140
|
reflection.klass
|
130
141
|
end
|
131
142
|
|
132
|
-
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
|
133
|
-
# through association's scope)
|
134
|
-
def target_scope
|
135
|
-
AssociationRelation.create(klass, self).merge!(klass.all)
|
136
|
-
end
|
137
|
-
|
138
143
|
def extensions
|
139
144
|
extensions = klass.default_extensions | reflection.extensions
|
140
145
|
|
@@ -195,6 +200,37 @@ module ActiveRecord
|
|
195
200
|
end
|
196
201
|
|
197
202
|
private
|
203
|
+
def find_target
|
204
|
+
scope = self.scope
|
205
|
+
return scope.to_a if skip_statement_cache?(scope)
|
206
|
+
|
207
|
+
sc = reflection.association_scope_cache(klass, owner) do |params|
|
208
|
+
as = AssociationScope.create { params.bind }
|
209
|
+
target_scope.merge!(as.scope(self))
|
210
|
+
end
|
211
|
+
|
212
|
+
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
213
|
+
sc.execute(binds, klass.connection) { |record| set_inverse_instance(record) } || []
|
214
|
+
end
|
215
|
+
|
216
|
+
# The scope for this association.
|
217
|
+
#
|
218
|
+
# Note that the association_scope is merged into the target_scope only when the
|
219
|
+
# scope method is called. This is because at that point the call may be surrounded
|
220
|
+
# by scope.scoping { ... } or unscoped { ... } etc, which affects the scope which
|
221
|
+
# actually gets built.
|
222
|
+
def association_scope
|
223
|
+
if klass
|
224
|
+
@association_scope ||= AssociationScope.scope(self)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
|
229
|
+
# through association's scope)
|
230
|
+
def target_scope
|
231
|
+
AssociationRelation.create(klass, self).merge!(klass.scope_for_association)
|
232
|
+
end
|
233
|
+
|
198
234
|
def scope_for_create
|
199
235
|
scope.scope_for_create
|
200
236
|
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,15 +48,11 @@ 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
|
-
table.create_join(table, table.create_on(constraint))
|
55
|
+
table.create_join(table, table.create_on(constraint), Arel::Nodes::LeadingJoin)
|
58
56
|
end
|
59
57
|
|
60
58
|
def last_chain_scope(scope, reflection, owner)
|
@@ -136,6 +134,12 @@ module ActiveRecord
|
|
136
134
|
|
137
135
|
if scope_chain_item == chain_head.scope
|
138
136
|
scope.merge! item.except(:where, :includes, :unscope, :order)
|
137
|
+
elsif !item.references_values.empty?
|
138
|
+
join_dependency = item.construct_join_dependency(
|
139
|
+
item.eager_load_values | item.includes_values, Arel::Nodes::OuterJoin
|
140
|
+
)
|
141
|
+
scope.joins!(*item.joins_values, join_dependency)
|
142
|
+
scope.left_outer_joins!(*item.left_outer_joins_values)
|
139
143
|
end
|
140
144
|
|
141
145
|
reflection.all_includes do
|
@@ -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
|
@@ -19,10 +19,6 @@ module ActiveRecord
|
|
19
19
|
owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
|
20
20
|
end
|
21
21
|
|
22
|
-
def different_target?(record)
|
23
|
-
super || record.class != klass
|
24
|
-
end
|
25
|
-
|
26
22
|
def inverse_reflection_for(record)
|
27
23
|
reflection.polymorphic_inverse_of(record.class)
|
28
24
|
end
|
@@ -27,40 +27,32 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
27
27
|
"Please choose a different association name."
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
reflection = create_reflection model, name, scope, options, extension
|
30
|
+
reflection = create_reflection(model, name, scope, options, &block)
|
32
31
|
define_accessors model, reflection
|
33
32
|
define_callbacks model, reflection
|
34
33
|
define_validations model, reflection
|
35
34
|
reflection
|
36
35
|
end
|
37
36
|
|
38
|
-
def self.create_reflection(model, name, scope, options,
|
37
|
+
def self.create_reflection(model, name, scope, options, &block)
|
39
38
|
raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
|
40
39
|
|
41
40
|
validate_options(options)
|
42
41
|
|
43
|
-
|
42
|
+
extension = define_extensions(model, name, &block)
|
43
|
+
options[:extend] = [*options[:extend], extension] if extension
|
44
|
+
|
45
|
+
scope = build_scope(scope)
|
44
46
|
|
45
47
|
ActiveRecord::Reflection.create(macro, name, scope, options, model)
|
46
48
|
end
|
47
49
|
|
48
|
-
def self.build_scope(scope
|
49
|
-
new_scope = scope
|
50
|
-
|
50
|
+
def self.build_scope(scope)
|
51
51
|
if scope && scope.arity == 0
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
if extension
|
56
|
-
new_scope = wrap_scope new_scope, extension
|
52
|
+
proc { instance_exec(&scope) }
|
53
|
+
else
|
54
|
+
scope
|
57
55
|
end
|
58
|
-
|
59
|
-
new_scope
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.wrap_scope(scope, extension)
|
63
|
-
scope
|
64
56
|
end
|
65
57
|
|
66
58
|
def self.macro
|
@@ -136,5 +128,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
136
128
|
name = reflection.name
|
137
129
|
model.before_destroy lambda { |o| o.association(name).handle_dependency }
|
138
130
|
end
|
131
|
+
|
132
|
+
private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
|
133
|
+
:define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
|
134
|
+
:valid_dependent_options, :check_dependent_options, :add_destroy_callbacks
|
139
135
|
end
|
140
136
|
end
|
@@ -21,58 +21,16 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
21
21
|
add_default_callbacks(model, reflection) if reflection.options[:default]
|
22
22
|
end
|
23
23
|
|
24
|
-
def self.define_accessors(mixin, reflection)
|
25
|
-
super
|
26
|
-
add_counter_cache_methods mixin
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.add_counter_cache_methods(mixin)
|
30
|
-
return if mixin.method_defined? :belongs_to_counter_cache_after_update
|
31
|
-
|
32
|
-
mixin.class_eval do
|
33
|
-
def belongs_to_counter_cache_after_update(reflection)
|
34
|
-
foreign_key = reflection.foreign_key
|
35
|
-
cache_column = reflection.counter_cache_column
|
36
|
-
|
37
|
-
if (@_after_replace_counter_called ||= false)
|
38
|
-
@_after_replace_counter_called = false
|
39
|
-
elsif association(reflection.name).target_changed?
|
40
|
-
if reflection.polymorphic?
|
41
|
-
model = attribute_in_database(reflection.foreign_type).try(:constantize)
|
42
|
-
model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
|
43
|
-
else
|
44
|
-
model = reflection.klass
|
45
|
-
model_was = reflection.klass
|
46
|
-
end
|
47
|
-
|
48
|
-
foreign_key_was = attribute_before_last_save foreign_key
|
49
|
-
foreign_key = attribute_in_database foreign_key
|
50
|
-
|
51
|
-
if foreign_key && model.respond_to?(:increment_counter)
|
52
|
-
foreign_key = counter_cache_target(reflection, model, foreign_key)
|
53
|
-
model.increment_counter(cache_column, foreign_key)
|
54
|
-
end
|
55
|
-
|
56
|
-
if foreign_key_was && model_was.respond_to?(:decrement_counter)
|
57
|
-
foreign_key_was = counter_cache_target(reflection, model_was, foreign_key_was)
|
58
|
-
model_was.decrement_counter(cache_column, foreign_key_was)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
def counter_cache_target(reflection, model, foreign_key)
|
65
|
-
primary_key = reflection.association_primary_key(model)
|
66
|
-
model.unscoped.where!(primary_key => foreign_key)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
24
|
def self.add_counter_cache_callbacks(model, reflection)
|
72
25
|
cache_column = reflection.counter_cache_column
|
73
26
|
|
74
27
|
model.after_update lambda { |record|
|
75
|
-
|
28
|
+
association = association(reflection.name)
|
29
|
+
|
30
|
+
if association.target_changed?
|
31
|
+
association.increment_counters
|
32
|
+
association.decrement_counters_before_last_save
|
33
|
+
end
|
76
34
|
}
|
77
35
|
|
78
36
|
klass = reflection.class_name.safe_constantize
|
@@ -116,19 +74,25 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
116
74
|
|
117
75
|
def self.add_touch_callbacks(model, reflection)
|
118
76
|
foreign_key = reflection.foreign_key
|
119
|
-
|
77
|
+
name = reflection.name
|
120
78
|
touch = reflection.options[:touch]
|
121
79
|
|
122
80
|
callback = lambda { |changes_method| lambda { |record|
|
123
|
-
BelongsTo.touch_record(record, record.send(changes_method), foreign_key,
|
81
|
+
BelongsTo.touch_record(record, record.send(changes_method), foreign_key, name, touch, belongs_to_touch_method)
|
124
82
|
}}
|
125
83
|
|
126
|
-
|
84
|
+
if reflection.counter_cache_column
|
85
|
+
touch_callback = callback.(:saved_changes)
|
86
|
+
update_callback = lambda { |record|
|
87
|
+
instance_exec(record, &touch_callback) unless association(reflection.name).target_changed?
|
88
|
+
}
|
89
|
+
model.after_update update_callback, if: :saved_changes?
|
90
|
+
else
|
127
91
|
model.after_create callback.(:saved_changes), if: :saved_changes?
|
92
|
+
model.after_update callback.(:saved_changes), if: :saved_changes?
|
128
93
|
model.after_destroy callback.(:changes_to_save)
|
129
94
|
end
|
130
95
|
|
131
|
-
model.after_update callback.(:saved_changes), if: :saved_changes?
|
132
96
|
model.after_touch callback.(:changes_to_save)
|
133
97
|
end
|
134
98
|
|
@@ -159,5 +123,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
159
123
|
model.validates_presence_of reflection.name, message: :required
|
160
124
|
end
|
161
125
|
end
|
126
|
+
|
127
|
+
private_class_method :macro, :valid_options, :valid_dependent_options, :define_callbacks, :define_validations,
|
128
|
+
:add_counter_cache_callbacks, :add_touch_callbacks, :add_default_callbacks, :add_destroy_callbacks
|
162
129
|
end
|
163
130
|
end
|
@@ -22,9 +22,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
22
22
|
|
23
23
|
def self.define_extensions(model, name, &block)
|
24
24
|
if block_given?
|
25
|
-
extension_module_name = "#{
|
25
|
+
extension_module_name = "#{name.to_s.camelize}AssociationExtension"
|
26
26
|
extension = Module.new(&block)
|
27
|
-
model.
|
27
|
+
model.const_set(extension_module_name, extension)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -67,16 +67,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
67
67
|
CODE
|
68
68
|
end
|
69
69
|
|
70
|
-
|
71
|
-
if scope
|
72
|
-
if scope.arity > 0
|
73
|
-
proc { |owner| instance_exec(owner, &scope).extending(mod) }
|
74
|
-
else
|
75
|
-
proc { instance_exec(&scope).extending(mod) }
|
76
|
-
end
|
77
|
-
else
|
78
|
-
proc { extending(mod) }
|
79
|
-
end
|
80
|
-
end
|
70
|
+
private_class_method :valid_options, :define_callback, :define_extensions, :define_readers, :define_writers
|
81
71
|
end
|
82
72
|
end
|