activerecord 6.1.7 → 7.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +92 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +96 -16
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -10,6 +10,7 @@ module ActiveRecord
|
|
10
10
|
included do
|
11
11
|
class_attribute :_reflections, instance_writer: false, default: {}
|
12
12
|
class_attribute :aggregate_reflections, instance_writer: false, default: {}
|
13
|
+
class_attribute :automatic_scope_inversing, instance_writer: false, default: false
|
13
14
|
end
|
14
15
|
|
15
16
|
class << self
|
@@ -45,6 +46,8 @@ module ActiveRecord
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
49
|
+
# = Active Record Reflection
|
50
|
+
#
|
48
51
|
# \Reflection enables the ability to examine the associations and aggregations of
|
49
52
|
# Active Record classes and objects. This information, for example,
|
50
53
|
# can be used in a form builder that takes an Active Record object
|
@@ -115,7 +118,7 @@ module ActiveRecord
|
|
115
118
|
reflections[association.to_s]
|
116
119
|
end
|
117
120
|
|
118
|
-
def _reflect_on_association(association)
|
121
|
+
def _reflect_on_association(association) # :nodoc:
|
119
122
|
_reflections[association.to_s]
|
120
123
|
end
|
121
124
|
|
@@ -127,6 +130,14 @@ module ActiveRecord
|
|
127
130
|
def clear_reflections_cache # :nodoc:
|
128
131
|
@__reflections = nil
|
129
132
|
end
|
133
|
+
|
134
|
+
private
|
135
|
+
def inherited(subclass)
|
136
|
+
super
|
137
|
+
subclass.class_eval do
|
138
|
+
@__reflections = nil
|
139
|
+
end
|
140
|
+
end
|
130
141
|
end
|
131
142
|
|
132
143
|
# Holds all the methods that are shared between MacroReflection and ThroughReflection.
|
@@ -143,6 +154,14 @@ module ActiveRecord
|
|
143
154
|
# PolymorphicReflection
|
144
155
|
# RuntimeReflection
|
145
156
|
class AbstractReflection # :nodoc:
|
157
|
+
def initialize
|
158
|
+
@class_name = nil
|
159
|
+
@counter_cache_column = nil
|
160
|
+
@inverse_of = nil
|
161
|
+
@inverse_which_updates_counter_cache_defined = false
|
162
|
+
@inverse_which_updates_counter_cache = nil
|
163
|
+
end
|
164
|
+
|
146
165
|
def through_reflection?
|
147
166
|
false
|
148
167
|
end
|
@@ -182,10 +201,14 @@ module ActiveRecord
|
|
182
201
|
|
183
202
|
scope_chain_items.inject(klass_scope, &:merge!)
|
184
203
|
|
185
|
-
|
186
|
-
|
204
|
+
primary_key_column_names = Array(join_primary_key)
|
205
|
+
foreign_key_column_names = Array(join_foreign_key)
|
187
206
|
|
188
|
-
|
207
|
+
primary_foreign_key_pairs = primary_key_column_names.zip(foreign_key_column_names)
|
208
|
+
|
209
|
+
primary_foreign_key_pairs.each do |primary_key_column_name, foreign_key_column_name|
|
210
|
+
klass_scope.where!(table[primary_key_column_name].eq(foreign_table[foreign_key_column_name]))
|
211
|
+
end
|
189
212
|
|
190
213
|
if klass.finder_needs_type_condition?
|
191
214
|
klass_scope.where!(klass.send(:type_condition, table))
|
@@ -194,9 +217,9 @@ module ActiveRecord
|
|
194
217
|
klass_scope
|
195
218
|
end
|
196
219
|
|
197
|
-
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
220
|
+
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
198
221
|
if scope
|
199
|
-
[scope_for(build_scope(table, predicate_builder, klass))]
|
222
|
+
[scope_for(build_scope(table, predicate_builder, klass), record)]
|
200
223
|
else
|
201
224
|
[]
|
202
225
|
end
|
@@ -230,14 +253,17 @@ module ActiveRecord
|
|
230
253
|
end
|
231
254
|
|
232
255
|
def check_validity_of_inverse!
|
233
|
-
|
234
|
-
if
|
256
|
+
if !polymorphic? && has_inverse?
|
257
|
+
if inverse_of.nil?
|
235
258
|
raise InverseOfAssociationNotFoundError.new(self)
|
236
259
|
end
|
260
|
+
if inverse_of == self
|
261
|
+
raise InverseOfAssociationRecursiveError.new(self)
|
262
|
+
end
|
237
263
|
end
|
238
264
|
end
|
239
265
|
|
240
|
-
#
|
266
|
+
# We need to avoid the following situation:
|
241
267
|
#
|
242
268
|
# * An associated record is deleted via record.destroy
|
243
269
|
# * Hence the callbacks run, and they find a belongs_to on the record with a
|
@@ -248,10 +274,16 @@ module ActiveRecord
|
|
248
274
|
#
|
249
275
|
# Hence this method.
|
250
276
|
def inverse_which_updates_counter_cache
|
251
|
-
|
252
|
-
|
253
|
-
|
277
|
+
unless @inverse_which_updates_counter_cache_defined
|
278
|
+
if counter_cache_column
|
279
|
+
inverse_candidates = inverse_of ? [inverse_of] : klass.reflect_on_all_associations(:belongs_to)
|
280
|
+
@inverse_which_updates_counter_cache = inverse_candidates.find do |inverse|
|
281
|
+
inverse.counter_cache_column == counter_cache_column && (inverse.polymorphic? || inverse.klass == active_record)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
@inverse_which_updates_counter_cache_defined = true
|
254
285
|
end
|
286
|
+
@inverse_which_updates_counter_cache
|
255
287
|
end
|
256
288
|
alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
|
257
289
|
|
@@ -293,6 +325,12 @@ module ActiveRecord
|
|
293
325
|
options[:strict_loading]
|
294
326
|
end
|
295
327
|
|
328
|
+
def strict_loading_violation_message(owner)
|
329
|
+
message = +"`#{owner}` is marked for strict_loading."
|
330
|
+
message << " The #{polymorphic? ? "polymorphic association" : "#{klass} association"}"
|
331
|
+
message << " named `:#{name}` cannot be lazily loaded."
|
332
|
+
end
|
333
|
+
|
296
334
|
protected
|
297
335
|
def actual_source_reflection # FIXME: this is a horrible name
|
298
336
|
self
|
@@ -306,6 +344,12 @@ module ActiveRecord
|
|
306
344
|
def primary_key(klass)
|
307
345
|
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
308
346
|
end
|
347
|
+
|
348
|
+
def ensure_option_not_given_as_class!(option_name)
|
349
|
+
if options[option_name] && options[option_name].class == Class
|
350
|
+
raise ArgumentError, "A class was passed to `:#{option_name}` but we are expecting a string."
|
351
|
+
end
|
352
|
+
end
|
309
353
|
end
|
310
354
|
|
311
355
|
# Base class for AggregateReflection and AssociationReflection. Objects of
|
@@ -330,6 +374,7 @@ module ActiveRecord
|
|
330
374
|
attr_reader :plural_name # :nodoc:
|
331
375
|
|
332
376
|
def initialize(name, scope, options, active_record)
|
377
|
+
super()
|
333
378
|
@name = name
|
334
379
|
@scope = scope
|
335
380
|
@options = options
|
@@ -337,6 +382,7 @@ module ActiveRecord
|
|
337
382
|
@klass = options[:anonymous_class]
|
338
383
|
@plural_name = active_record.pluralize_table_names ?
|
339
384
|
name.to_s.pluralize : name.to_s
|
385
|
+
validate_reflection!
|
340
386
|
end
|
341
387
|
|
342
388
|
def autosave=(autosave)
|
@@ -388,11 +434,22 @@ module ActiveRecord
|
|
388
434
|
def derive_class_name
|
389
435
|
name.to_s.camelize
|
390
436
|
end
|
437
|
+
|
438
|
+
def validate_reflection!
|
439
|
+
return unless options[:foreign_key].is_a?(Array)
|
440
|
+
|
441
|
+
message = <<~MSG.squish
|
442
|
+
Passing #{options[:foreign_key]} array to :foreign_key option
|
443
|
+
on the #{active_record}##{name} association is not supported.
|
444
|
+
Use the query_constraints: #{options[:foreign_key]} option instead to represent a composite foreign key.
|
445
|
+
MSG
|
446
|
+
raise ArgumentError, message
|
447
|
+
end
|
391
448
|
end
|
392
449
|
|
393
450
|
# Holds all the metadata about an aggregation as it was specified in the
|
394
451
|
# Active Record class.
|
395
|
-
class AggregateReflection < MacroReflection
|
452
|
+
class AggregateReflection < MacroReflection # :nodoc:
|
396
453
|
def mapping
|
397
454
|
mapping = options[:mapping] || [name, name]
|
398
455
|
mapping.first.is_a?(Array) ? mapping : [mapping]
|
@@ -401,12 +458,29 @@ module ActiveRecord
|
|
401
458
|
|
402
459
|
# Holds all the metadata about an association as it was specified in the
|
403
460
|
# Active Record class.
|
404
|
-
class AssociationReflection < MacroReflection
|
461
|
+
class AssociationReflection < MacroReflection # :nodoc:
|
405
462
|
def compute_class(name)
|
406
463
|
if polymorphic?
|
407
464
|
raise ArgumentError, "Polymorphic associations do not support computing the class."
|
408
465
|
end
|
409
|
-
|
466
|
+
|
467
|
+
begin
|
468
|
+
klass = active_record.send(:compute_type, name)
|
469
|
+
rescue NameError => error
|
470
|
+
if error.name.match?(/(?:\A|::)#{name}\z/)
|
471
|
+
message = "Missing model class #{name} for the #{active_record}##{self.name} association."
|
472
|
+
message += " You can specify a different model class with the :class_name option." unless options[:class_name]
|
473
|
+
raise NameError.new(message, name)
|
474
|
+
else
|
475
|
+
raise
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
unless klass < ActiveRecord::Base
|
480
|
+
raise ArgumentError, "The #{name} model class for the #{active_record}##{self.name} association is not an ActiveRecord::Base subclass."
|
481
|
+
end
|
482
|
+
|
483
|
+
klass
|
410
484
|
end
|
411
485
|
|
412
486
|
attr_reader :type, :foreign_type
|
@@ -416,11 +490,12 @@ module ActiveRecord
|
|
416
490
|
super
|
417
491
|
@type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
|
418
492
|
@foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
|
419
|
-
@
|
493
|
+
@join_table = nil
|
494
|
+
@foreign_key = nil
|
495
|
+
@association_foreign_key = nil
|
496
|
+
@association_primary_key = nil
|
420
497
|
|
421
|
-
|
422
|
-
raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
|
423
|
-
end
|
498
|
+
ensure_option_not_given_as_class!(:class_name)
|
424
499
|
end
|
425
500
|
|
426
501
|
def association_scope_cache(klass, owner, &block)
|
@@ -431,16 +506,24 @@ module ActiveRecord
|
|
431
506
|
klass.cached_find_by_statement(key, &block)
|
432
507
|
end
|
433
508
|
|
434
|
-
def constructable? # :nodoc:
|
435
|
-
@constructable
|
436
|
-
end
|
437
|
-
|
438
509
|
def join_table
|
439
510
|
@join_table ||= -(options[:join_table]&.to_s || derive_join_table)
|
440
511
|
end
|
441
512
|
|
442
|
-
def foreign_key
|
443
|
-
@foreign_key ||=
|
513
|
+
def foreign_key(infer_from_inverse_of: true)
|
514
|
+
@foreign_key ||= if options[:query_constraints]
|
515
|
+
options[:query_constraints].map { |fk| fk.to_s.freeze }.freeze
|
516
|
+
elsif options[:foreign_key]
|
517
|
+
options[:foreign_key].to_s
|
518
|
+
else
|
519
|
+
derived_fk = derive_foreign_key(infer_from_inverse_of: infer_from_inverse_of)
|
520
|
+
|
521
|
+
if active_record.has_query_constraints?
|
522
|
+
derived_fk = derive_fk_query_constraints(derived_fk)
|
523
|
+
end
|
524
|
+
|
525
|
+
derived_fk
|
526
|
+
end
|
444
527
|
end
|
445
528
|
|
446
529
|
def association_foreign_key
|
@@ -452,36 +535,62 @@ module ActiveRecord
|
|
452
535
|
end
|
453
536
|
|
454
537
|
def active_record_primary_key
|
455
|
-
|
538
|
+
custom_primary_key = options[:primary_key]
|
539
|
+
@active_record_primary_key ||= if custom_primary_key
|
540
|
+
if custom_primary_key.is_a?(Array)
|
541
|
+
custom_primary_key.map { |pk| pk.to_s.freeze }.freeze
|
542
|
+
else
|
543
|
+
custom_primary_key.to_s.freeze
|
544
|
+
end
|
545
|
+
elsif active_record.has_query_constraints? || options[:query_constraints]
|
546
|
+
active_record.query_constraints_list
|
547
|
+
elsif active_record.composite_primary_key?
|
548
|
+
# If active_record has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
|
549
|
+
primary_key = primary_key(active_record)
|
550
|
+
primary_key.include?("id") ? "id" : primary_key.freeze
|
551
|
+
else
|
552
|
+
primary_key(active_record).freeze
|
553
|
+
end
|
456
554
|
end
|
457
555
|
|
458
556
|
def join_primary_key(klass = nil)
|
459
557
|
foreign_key
|
460
558
|
end
|
461
559
|
|
560
|
+
def join_primary_type
|
561
|
+
type
|
562
|
+
end
|
563
|
+
|
462
564
|
def join_foreign_key
|
463
565
|
active_record_primary_key
|
464
566
|
end
|
465
567
|
|
466
568
|
def check_validity!
|
467
569
|
check_validity_of_inverse!
|
570
|
+
|
571
|
+
if !polymorphic? && (klass.composite_primary_key? || active_record.composite_primary_key?)
|
572
|
+
if (has_one? || collection?) && Array(active_record_primary_key).length != Array(foreign_key).length
|
573
|
+
raise CompositePrimaryKeyMismatchError.new(self)
|
574
|
+
elsif belongs_to? && Array(association_primary_key).length != Array(foreign_key).length
|
575
|
+
raise CompositePrimaryKeyMismatchError.new(self)
|
576
|
+
end
|
577
|
+
end
|
468
578
|
end
|
469
579
|
|
470
|
-
def
|
580
|
+
def check_eager_loadable!
|
471
581
|
return unless scope
|
472
582
|
|
473
583
|
unless scope.arity == 0
|
474
584
|
raise ArgumentError, <<-MSG.squish
|
475
585
|
The association scope '#{name}' is instance dependent (the scope
|
476
|
-
block takes an argument).
|
477
|
-
not supported.
|
586
|
+
block takes an argument). Eager loading instance dependent scopes
|
587
|
+
is not supported.
|
478
588
|
MSG
|
479
589
|
end
|
480
590
|
end
|
481
|
-
alias :check_eager_loadable! :check_preloadable!
|
482
591
|
|
483
592
|
def join_id_for(owner) # :nodoc:
|
484
|
-
owner
|
593
|
+
Array(join_foreign_key).map { |key| owner._read_attribute(key) }
|
485
594
|
end
|
486
595
|
|
487
596
|
def through_reflection
|
@@ -563,8 +672,9 @@ module ActiveRecord
|
|
563
672
|
options[:polymorphic]
|
564
673
|
end
|
565
674
|
|
566
|
-
|
567
|
-
|
675
|
+
def polymorphic_name
|
676
|
+
active_record.polymorphic_name
|
677
|
+
end
|
568
678
|
|
569
679
|
def add_as_source(seed)
|
570
680
|
seed
|
@@ -583,10 +693,6 @@ module ActiveRecord
|
|
583
693
|
end
|
584
694
|
|
585
695
|
private
|
586
|
-
def calculate_constructable(macro, options)
|
587
|
-
true
|
588
|
-
end
|
589
|
-
|
590
696
|
# Attempts to find the inverse association name automatically.
|
591
697
|
# If it cannot find a suitable inverse association name, it returns
|
592
698
|
# +nil+.
|
@@ -605,7 +711,9 @@ module ActiveRecord
|
|
605
711
|
|
606
712
|
begin
|
607
713
|
reflection = klass._reflect_on_association(inverse_name)
|
608
|
-
rescue NameError
|
714
|
+
rescue NameError => error
|
715
|
+
raise unless error.name.to_s == class_name
|
716
|
+
|
609
717
|
# Give up: we couldn't compute the klass type so we won't be able
|
610
718
|
# to find any associations either.
|
611
719
|
reflection = false
|
@@ -623,9 +731,10 @@ module ActiveRecord
|
|
623
731
|
# with the current reflection's klass name.
|
624
732
|
def valid_inverse_reflection?(reflection)
|
625
733
|
reflection &&
|
734
|
+
reflection != self &&
|
626
735
|
foreign_key == reflection.foreign_key &&
|
627
736
|
klass <= reflection.active_record &&
|
628
|
-
can_find_inverse_of_automatically?(reflection)
|
737
|
+
can_find_inverse_of_automatically?(reflection, true)
|
629
738
|
end
|
630
739
|
|
631
740
|
# Checks to see if the reflection doesn't have any options that prevent
|
@@ -634,14 +743,25 @@ module ActiveRecord
|
|
634
743
|
# have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
|
635
744
|
# Third, we must not have options such as <tt>:foreign_key</tt>
|
636
745
|
# which prevent us from correctly guessing the inverse association.
|
637
|
-
|
638
|
-
# Anything with a scope can additionally ruin our attempt at finding an
|
639
|
-
# inverse, so we exclude reflections with scopes.
|
640
|
-
def can_find_inverse_of_automatically?(reflection)
|
746
|
+
def can_find_inverse_of_automatically?(reflection, inverse_reflection = false)
|
641
747
|
reflection.options[:inverse_of] != false &&
|
642
|
-
|
643
|
-
!
|
748
|
+
!reflection.options[:through] &&
|
749
|
+
!reflection.options[:foreign_key] &&
|
750
|
+
scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
|
751
|
+
end
|
752
|
+
|
753
|
+
# Scopes on the potential inverse reflection prevent automatic
|
754
|
+
# <tt>inverse_of</tt>, since the scope could exclude the owner record
|
755
|
+
# we would inverse from. Scopes on the reflection itself allow for
|
756
|
+
# automatic <tt>inverse_of</tt> as long as
|
757
|
+
# <tt>config.active_record.automatic_scope_inversing<tt> is set to
|
758
|
+
# +true+ (the default for new applications).
|
759
|
+
def scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
|
760
|
+
if inverse_reflection
|
644
761
|
!reflection.scope
|
762
|
+
else
|
763
|
+
!reflection.scope || reflection.klass.automatic_scope_inversing
|
764
|
+
end
|
645
765
|
end
|
646
766
|
|
647
767
|
def derive_class_name
|
@@ -650,13 +770,55 @@ module ActiveRecord
|
|
650
770
|
class_name.camelize
|
651
771
|
end
|
652
772
|
|
653
|
-
def derive_foreign_key
|
773
|
+
def derive_foreign_key(infer_from_inverse_of: true)
|
654
774
|
if belongs_to?
|
655
775
|
"#{name}_id"
|
656
776
|
elsif options[:as]
|
657
777
|
"#{options[:as]}_id"
|
778
|
+
elsif options[:inverse_of] && infer_from_inverse_of
|
779
|
+
inverse_of.foreign_key(infer_from_inverse_of: false)
|
658
780
|
else
|
659
|
-
active_record.
|
781
|
+
active_record.model_name.to_s.foreign_key
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
def derive_fk_query_constraints(foreign_key)
|
786
|
+
primary_query_constraints = active_record.query_constraints_list
|
787
|
+
owner_pk = active_record.primary_key
|
788
|
+
|
789
|
+
if primary_query_constraints.size > 2
|
790
|
+
raise ArgumentError, <<~MSG.squish
|
791
|
+
The query constraints list on the `#{active_record}` model has more than 2
|
792
|
+
attributes. Active Record is unable to derive the query constraints
|
793
|
+
for the association. You need to explicitly define the query constraints
|
794
|
+
for this association.
|
795
|
+
MSG
|
796
|
+
end
|
797
|
+
|
798
|
+
if !primary_query_constraints.include?(owner_pk)
|
799
|
+
raise ArgumentError, <<~MSG.squish
|
800
|
+
The query constraints on the `#{active_record}` model does not include the primary
|
801
|
+
key so Active Record is unable to derive the foreign key constraints for
|
802
|
+
the association. You need to explicitly define the query constraints for this
|
803
|
+
association.
|
804
|
+
MSG
|
805
|
+
end
|
806
|
+
|
807
|
+
return foreign_key if primary_query_constraints.include?(foreign_key)
|
808
|
+
|
809
|
+
first_key, last_key = primary_query_constraints
|
810
|
+
|
811
|
+
if first_key == owner_pk
|
812
|
+
[foreign_key, last_key.to_s]
|
813
|
+
elsif last_key == owner_pk
|
814
|
+
[first_key.to_s, foreign_key]
|
815
|
+
else
|
816
|
+
raise ArgumentError, <<~MSG.squish
|
817
|
+
Active Record couldn't correctly interpret the query constraints
|
818
|
+
for the `#{active_record}` model. The query constraints on `#{active_record}` are
|
819
|
+
`#{primary_query_constraints}` and the foreign key is `#{foreign_key}`.
|
820
|
+
You need to explicitly set the query constraints for this association.
|
821
|
+
MSG
|
660
822
|
end
|
661
823
|
end
|
662
824
|
|
@@ -691,11 +853,6 @@ module ActiveRecord
|
|
691
853
|
Associations::HasOneAssociation
|
692
854
|
end
|
693
855
|
end
|
694
|
-
|
695
|
-
private
|
696
|
-
def calculate_constructable(macro, options)
|
697
|
-
!options[:through]
|
698
|
-
end
|
699
856
|
end
|
700
857
|
|
701
858
|
class BelongsToReflection < AssociationReflection # :nodoc:
|
@@ -714,7 +871,17 @@ module ActiveRecord
|
|
714
871
|
# klass option is necessary to support loading polymorphic associations
|
715
872
|
def association_primary_key(klass = nil)
|
716
873
|
if primary_key = options[:primary_key]
|
717
|
-
@association_primary_key ||=
|
874
|
+
@association_primary_key ||= if primary_key.is_a?(Array)
|
875
|
+
primary_key.map { |pk| pk.to_s.freeze }.freeze
|
876
|
+
else
|
877
|
+
-primary_key.to_s
|
878
|
+
end
|
879
|
+
elsif (klass || self.klass).has_query_constraints? || options[:query_constraints]
|
880
|
+
(klass || self.klass).composite_query_constraints_list
|
881
|
+
elsif (klass || self.klass).composite_primary_key?
|
882
|
+
# If klass has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
|
883
|
+
primary_key = (klass || self.klass).primary_key
|
884
|
+
primary_key.include?("id") ? "id" : primary_key
|
718
885
|
else
|
719
886
|
primary_key(klass || self.klass)
|
720
887
|
end
|
@@ -733,13 +900,9 @@ module ActiveRecord
|
|
733
900
|
end
|
734
901
|
|
735
902
|
private
|
736
|
-
def can_find_inverse_of_automatically?(
|
903
|
+
def can_find_inverse_of_automatically?(*)
|
737
904
|
!polymorphic? && super
|
738
905
|
end
|
739
|
-
|
740
|
-
def calculate_constructable(macro, options)
|
741
|
-
!polymorphic?
|
742
|
-
end
|
743
906
|
end
|
744
907
|
|
745
908
|
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
|
@@ -752,14 +915,17 @@ module ActiveRecord
|
|
752
915
|
|
753
916
|
# Holds all the metadata about a :through association as it was specified
|
754
917
|
# in the Active Record class.
|
755
|
-
class ThroughReflection < AbstractReflection
|
918
|
+
class ThroughReflection < AbstractReflection # :nodoc:
|
756
919
|
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
|
757
920
|
:active_record_primary_key, :join_foreign_key, to: :source_reflection
|
758
921
|
|
759
922
|
def initialize(delegate_reflection)
|
923
|
+
super()
|
760
924
|
@delegate_reflection = delegate_reflection
|
761
925
|
@klass = delegate_reflection.options[:anonymous_class]
|
762
926
|
@source_reflection_name = delegate_reflection.options[:source]
|
927
|
+
|
928
|
+
ensure_option_not_given_as_class!(:source_type)
|
763
929
|
end
|
764
930
|
|
765
931
|
def through_reflection?
|
@@ -840,8 +1006,8 @@ module ActiveRecord
|
|
840
1006
|
source_reflection.scopes + super
|
841
1007
|
end
|
842
1008
|
|
843
|
-
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
844
|
-
source_reflection.join_scopes(table, predicate_builder, klass) + super
|
1009
|
+
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
1010
|
+
source_reflection.join_scopes(table, predicate_builder, klass, record) + super
|
845
1011
|
end
|
846
1012
|
|
847
1013
|
def has_scope?
|
@@ -888,24 +1054,23 @@ module ActiveRecord
|
|
888
1054
|
end
|
889
1055
|
|
890
1056
|
def source_reflection_name # :nodoc:
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
1057
|
+
@source_reflection_name ||= begin
|
1058
|
+
names = [name.to_s.singularize, name].collect(&:to_sym).uniq
|
1059
|
+
names = names.find_all { |n|
|
1060
|
+
through_reflection.klass._reflect_on_association(n)
|
1061
|
+
}
|
1062
|
+
|
1063
|
+
if names.length > 1
|
1064
|
+
raise AmbiguousSourceReflectionForThroughAssociation.new(
|
1065
|
+
active_record.name,
|
1066
|
+
macro,
|
1067
|
+
name,
|
1068
|
+
options,
|
1069
|
+
source_reflection_names
|
1070
|
+
)
|
1071
|
+
end
|
1072
|
+
names.first
|
906
1073
|
end
|
907
|
-
|
908
|
-
@source_reflection_name = names.first
|
909
1074
|
end
|
910
1075
|
|
911
1076
|
def source_options
|
@@ -1009,13 +1174,14 @@ module ActiveRecord
|
|
1009
1174
|
:name, :scope_for, to: :@reflection
|
1010
1175
|
|
1011
1176
|
def initialize(reflection, previous_reflection)
|
1177
|
+
super()
|
1012
1178
|
@reflection = reflection
|
1013
1179
|
@previous_reflection = previous_reflection
|
1014
1180
|
end
|
1015
1181
|
|
1016
|
-
def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
|
1017
|
-
scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
|
1018
|
-
scopes << build_scope(table, predicate_builder, klass).instance_exec(
|
1182
|
+
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
1183
|
+
scopes = @previous_reflection.join_scopes(table, predicate_builder, klass, record) + super
|
1184
|
+
scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
|
1019
1185
|
end
|
1020
1186
|
|
1021
1187
|
def constraints
|
@@ -1034,6 +1200,7 @@ module ActiveRecord
|
|
1034
1200
|
delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
|
1035
1201
|
|
1036
1202
|
def initialize(reflection, association)
|
1203
|
+
super()
|
1037
1204
|
@reflection = reflection
|
1038
1205
|
@association = association
|
1039
1206
|
end
|
@@ -5,11 +5,27 @@ module ActiveRecord
|
|
5
5
|
class BatchEnumerator
|
6
6
|
include Enumerable
|
7
7
|
|
8
|
-
def initialize(of: 1000, start: nil, finish: nil, relation:)
|
8
|
+
def initialize(of: 1000, start: nil, finish: nil, relation:, order: :asc, use_ranges: nil) # :nodoc:
|
9
9
|
@of = of
|
10
10
|
@relation = relation
|
11
11
|
@start = start
|
12
12
|
@finish = finish
|
13
|
+
@order = order
|
14
|
+
@use_ranges = use_ranges
|
15
|
+
end
|
16
|
+
|
17
|
+
# The primary key value from which the BatchEnumerator starts, inclusive of the value.
|
18
|
+
attr_reader :start
|
19
|
+
|
20
|
+
# The primary key value at which the BatchEnumerator ends, inclusive of the value.
|
21
|
+
attr_reader :finish
|
22
|
+
|
23
|
+
# The relation from which the BatchEnumerator yields batches.
|
24
|
+
attr_reader :relation
|
25
|
+
|
26
|
+
# The size of the batches yielded by the BatchEnumerator.
|
27
|
+
def batch_size
|
28
|
+
@of
|
13
29
|
end
|
14
30
|
|
15
31
|
# Looping through a collection of records from the database (using the
|
@@ -33,11 +49,11 @@ module ActiveRecord
|
|
33
49
|
# Person.in_batches.each_record.with_index do |person, index|
|
34
50
|
# person.award_trophy(index + 1)
|
35
51
|
# end
|
36
|
-
def each_record
|
52
|
+
def each_record(&block)
|
37
53
|
return to_enum(:each_record) unless block_given?
|
38
54
|
|
39
|
-
@relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true).each do |relation|
|
40
|
-
relation.records.each
|
55
|
+
@relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true, order: @order).each do |relation|
|
56
|
+
relation.records.each(&block)
|
41
57
|
end
|
42
58
|
end
|
43
59
|
|
@@ -75,9 +91,9 @@ module ActiveRecord
|
|
75
91
|
# Person.in_batches.each do |relation|
|
76
92
|
# relation.update_all(awesome: true)
|
77
93
|
# end
|
78
|
-
def each
|
79
|
-
enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false)
|
80
|
-
return enum.each
|
94
|
+
def each(&block)
|
95
|
+
enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false, order: @order, use_ranges: @use_ranges)
|
96
|
+
return enum.each(&block) if block_given?
|
81
97
|
enum
|
82
98
|
end
|
83
99
|
end
|