activerecord 5.2.3 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +898 -532
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +5 -4
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +95 -42
- data/lib/active_record/associations/association_scope.rb +21 -21
- data/lib/active_record/associations/belongs_to_association.rb +50 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
- data/lib/active_record/associations/builder/association.rb +23 -21
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +10 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +31 -29
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +27 -28
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +54 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +71 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +48 -35
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +133 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +45 -8
- data/lib/active_record/autosave_association.rb +76 -47
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +293 -132
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +21 -17
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +203 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +381 -146
- data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -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 +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
- 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/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- 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/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- 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 +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- 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 +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +222 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +175 -187
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +285 -33
- data/lib/active_record/core.rb +308 -100
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +71 -17
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +32 -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 +197 -481
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +26 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +26 -22
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +34 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +141 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +205 -156
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +115 -58
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +402 -78
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +113 -101
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +157 -93
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +65 -40
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -7
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +58 -40
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +487 -199
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +108 -58
- data/lib/active_record/relation.rb +375 -104
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +6 -8
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +51 -8
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -43
- data/lib/active_record/tasks/database_tasks.rb +276 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +59 -117
- 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 +6 -3
- 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 +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -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 +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -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 +15 -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 +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -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 +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -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 +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -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 +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -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 +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +117 -32
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
|
7
7
|
def klass
|
8
8
|
type = owner[reflection.foreign_type]
|
9
|
-
type.presence && type
|
9
|
+
type.presence && owner.class.polymorphic_class_for(type)
|
10
10
|
end
|
11
11
|
|
12
12
|
def target_changed?
|
@@ -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
|
@@ -18,7 +18,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
18
18
|
end
|
19
19
|
self.extensions = []
|
20
20
|
|
21
|
-
VALID_OPTIONS = [
|
21
|
+
VALID_OPTIONS = [
|
22
|
+
:class_name, :anonymous_class, :primary_key, :foreign_key, :dependent, :validate, :inverse_of, :strict_loading
|
23
|
+
].freeze # :nodoc:
|
22
24
|
|
23
25
|
def self.build(model, name, scope, options, &block)
|
24
26
|
if model.dangerous_attribute_method?(name)
|
@@ -27,40 +29,32 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
27
29
|
"Please choose a different association name."
|
28
30
|
end
|
29
31
|
|
30
|
-
|
31
|
-
reflection = create_reflection model, name, scope, options, extension
|
32
|
+
reflection = create_reflection(model, name, scope, options, &block)
|
32
33
|
define_accessors model, reflection
|
33
34
|
define_callbacks model, reflection
|
34
35
|
define_validations model, reflection
|
35
36
|
reflection
|
36
37
|
end
|
37
38
|
|
38
|
-
def self.create_reflection(model, name, scope, options,
|
39
|
+
def self.create_reflection(model, name, scope, options, &block)
|
39
40
|
raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
|
40
41
|
|
41
42
|
validate_options(options)
|
42
43
|
|
43
|
-
|
44
|
+
extension = define_extensions(model, name, &block)
|
45
|
+
options[:extend] = [*options[:extend], extension] if extension
|
46
|
+
|
47
|
+
scope = build_scope(scope)
|
44
48
|
|
45
49
|
ActiveRecord::Reflection.create(macro, name, scope, options, model)
|
46
50
|
end
|
47
51
|
|
48
|
-
def self.build_scope(scope
|
49
|
-
new_scope = scope
|
50
|
-
|
52
|
+
def self.build_scope(scope)
|
51
53
|
if scope && scope.arity == 0
|
52
|
-
|
54
|
+
proc { instance_exec(&scope) }
|
55
|
+
else
|
56
|
+
scope
|
53
57
|
end
|
54
|
-
|
55
|
-
if extension
|
56
|
-
new_scope = wrap_scope new_scope, extension
|
57
|
-
end
|
58
|
-
|
59
|
-
new_scope
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.wrap_scope(scope, extension)
|
63
|
-
scope
|
64
58
|
end
|
65
59
|
|
66
60
|
def self.macro
|
@@ -80,7 +74,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
80
74
|
|
81
75
|
def self.define_callbacks(model, reflection)
|
82
76
|
if dependent = reflection.options[:dependent]
|
83
|
-
check_dependent_options(dependent)
|
77
|
+
check_dependent_options(dependent, model)
|
84
78
|
add_destroy_callbacks(model, reflection)
|
85
79
|
end
|
86
80
|
|
@@ -126,7 +120,11 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
126
120
|
raise NotImplementedError
|
127
121
|
end
|
128
122
|
|
129
|
-
def self.check_dependent_options(dependent)
|
123
|
+
def self.check_dependent_options(dependent, model)
|
124
|
+
if dependent == :destroy_async && !model.destroy_association_async_job
|
125
|
+
err_message = "ActiveJob is required to use destroy_async on associations"
|
126
|
+
raise ActiveRecord::ActiveJobRequiredError, err_message
|
127
|
+
end
|
130
128
|
unless valid_dependent_options.include? dependent
|
131
129
|
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
|
132
130
|
end
|
@@ -136,5 +134,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
136
134
|
name = reflection.name
|
137
135
|
model.before_destroy lambda { |o| o.association(name).handle_dependency }
|
138
136
|
end
|
137
|
+
|
138
|
+
private_class_method :build_scope, :macro, :valid_options, :validate_options, :define_extensions,
|
139
|
+
:define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations,
|
140
|
+
:valid_dependent_options, :check_dependent_options, :add_destroy_callbacks
|
139
141
|
end
|
140
142
|
end
|
@@ -7,11 +7,14 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
10
|
+
valid = super + [:counter_cache, :optional, :default]
|
11
|
+
valid += [:polymorphic, :foreign_type] if options[:polymorphic]
|
12
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
13
|
+
valid
|
11
14
|
end
|
12
15
|
|
13
16
|
def self.valid_dependent_options
|
14
|
-
[:destroy, :delete]
|
17
|
+
[:destroy, :delete, :destroy_async]
|
15
18
|
end
|
16
19
|
|
17
20
|
def self.define_callbacks(model, reflection)
|
@@ -21,58 +24,16 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
21
24
|
add_default_callbacks(model, reflection) if reflection.options[:default]
|
22
25
|
end
|
23
26
|
|
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
27
|
def self.add_counter_cache_callbacks(model, reflection)
|
72
28
|
cache_column = reflection.counter_cache_column
|
73
29
|
|
74
30
|
model.after_update lambda { |record|
|
75
|
-
|
31
|
+
association = association(reflection.name)
|
32
|
+
|
33
|
+
if association.target_changed?
|
34
|
+
association.increment_counters
|
35
|
+
association.decrement_counters_before_last_save
|
36
|
+
end
|
76
37
|
}
|
77
38
|
|
78
39
|
klass = reflection.class_name.safe_constantize
|
@@ -97,38 +58,44 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
97
58
|
|
98
59
|
if old_record
|
99
60
|
if touch != true
|
100
|
-
old_record.
|
61
|
+
old_record.public_send(touch_method, touch)
|
101
62
|
else
|
102
|
-
old_record.
|
63
|
+
old_record.public_send(touch_method)
|
103
64
|
end
|
104
65
|
end
|
105
66
|
end
|
106
67
|
|
107
|
-
record = o.
|
68
|
+
record = o.public_send name
|
108
69
|
if record && record.persisted?
|
109
70
|
if touch != true
|
110
|
-
record.
|
71
|
+
record.public_send(touch_method, touch)
|
111
72
|
else
|
112
|
-
record.
|
73
|
+
record.public_send(touch_method)
|
113
74
|
end
|
114
75
|
end
|
115
76
|
end
|
116
77
|
|
117
78
|
def self.add_touch_callbacks(model, reflection)
|
118
79
|
foreign_key = reflection.foreign_key
|
119
|
-
|
80
|
+
name = reflection.name
|
120
81
|
touch = reflection.options[:touch]
|
121
82
|
|
122
83
|
callback = lambda { |changes_method| lambda { |record|
|
123
|
-
BelongsTo.touch_record(record, record.send(changes_method), foreign_key,
|
84
|
+
BelongsTo.touch_record(record, record.send(changes_method), foreign_key, name, touch, belongs_to_touch_method)
|
124
85
|
}}
|
125
86
|
|
126
|
-
|
87
|
+
if reflection.counter_cache_column
|
88
|
+
touch_callback = callback.(:saved_changes)
|
89
|
+
update_callback = lambda { |record|
|
90
|
+
instance_exec(record, &touch_callback) unless association(reflection.name).target_changed?
|
91
|
+
}
|
92
|
+
model.after_update update_callback, if: :saved_changes?
|
93
|
+
else
|
127
94
|
model.after_create callback.(:saved_changes), if: :saved_changes?
|
95
|
+
model.after_update callback.(:saved_changes), if: :saved_changes?
|
128
96
|
model.after_destroy callback.(:changes_to_save)
|
129
97
|
end
|
130
98
|
|
131
|
-
model.after_update callback.(:saved_changes), if: :saved_changes?
|
132
99
|
model.after_touch callback.(:changes_to_save)
|
133
100
|
end
|
134
101
|
|
@@ -159,5 +126,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
159
126
|
model.validates_presence_of reflection.name, message: :required
|
160
127
|
end
|
161
128
|
end
|
129
|
+
|
130
|
+
private_class_method :macro, :valid_options, :valid_dependent_options, :define_callbacks, :define_validations,
|
131
|
+
:add_counter_cache_callbacks, :add_touch_callbacks, :add_default_callbacks, :add_destroy_callbacks
|
162
132
|
end
|
163
133
|
end
|
@@ -7,8 +7,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
11
|
-
:after_add, :before_remove, :after_remove, :extend]
|
10
|
+
super + [:before_add, :after_add, :before_remove, :after_remove, :extend]
|
12
11
|
end
|
13
12
|
|
14
13
|
def self.define_callbacks(model, reflection)
|
@@ -20,19 +19,21 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
20
19
|
}
|
21
20
|
end
|
22
21
|
|
23
|
-
def self.define_extensions(model, name)
|
22
|
+
def self.define_extensions(model, name, &block)
|
24
23
|
if block_given?
|
25
|
-
extension_module_name = "#{
|
26
|
-
extension = Module.new(&
|
27
|
-
model.
|
24
|
+
extension_module_name = "#{name.to_s.camelize}AssociationExtension"
|
25
|
+
extension = Module.new(&block)
|
26
|
+
model.const_set(extension_module_name, extension)
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
30
|
def self.define_callback(model, callback_name, name, options)
|
32
31
|
full_callback_name = "#{callback_name}_for_#{name}"
|
33
32
|
|
34
|
-
|
35
|
-
|
33
|
+
unless model.method_defined?(full_callback_name)
|
34
|
+
model.class_attribute(full_callback_name, instance_accessor: false, instance_predicate: false)
|
35
|
+
end
|
36
|
+
|
36
37
|
callbacks = Array(options[callback_name.to_sym]).map do |callback|
|
37
38
|
case callback
|
38
39
|
when Symbol
|
@@ -67,16 +68,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
67
68
|
CODE
|
68
69
|
end
|
69
70
|
|
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
|
71
|
+
private_class_method :valid_options, :define_callback, :define_extensions, :define_readers, :define_writers
|
81
72
|
end
|
82
73
|
end
|
@@ -2,39 +2,6 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord::Associations::Builder # :nodoc:
|
4
4
|
class HasAndBelongsToMany # :nodoc:
|
5
|
-
class JoinTableResolver # :nodoc:
|
6
|
-
KnownTable = Struct.new :join_table
|
7
|
-
|
8
|
-
class KnownClass # :nodoc:
|
9
|
-
def initialize(lhs_class, rhs_class_name)
|
10
|
-
@lhs_class = lhs_class
|
11
|
-
@rhs_class_name = rhs_class_name
|
12
|
-
@join_table = nil
|
13
|
-
end
|
14
|
-
|
15
|
-
def join_table
|
16
|
-
@join_table ||= [@lhs_class.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def klass
|
22
|
-
@lhs_class.send(:compute_type, @rhs_class_name)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.build(lhs_class, name, options)
|
27
|
-
if options[:join_table]
|
28
|
-
KnownTable.new options[:join_table].to_s
|
29
|
-
else
|
30
|
-
class_name = options.fetch(:class_name) {
|
31
|
-
name.to_s.camelize.singularize
|
32
|
-
}
|
33
|
-
KnownClass.new lhs_class, class_name.to_s
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
5
|
attr_reader :lhs_model, :association_name, :options
|
39
6
|
|
40
7
|
def initialize(association_name, lhs_model, options)
|
@@ -44,8 +11,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
44
11
|
end
|
45
12
|
|
46
13
|
def through_model
|
47
|
-
habtm = JoinTableResolver.build lhs_model, association_name, options
|
48
|
-
|
49
14
|
join_model = Class.new(ActiveRecord::Base) {
|
50
15
|
class << self
|
51
16
|
attr_accessor :left_model
|
@@ -56,7 +21,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
56
21
|
end
|
57
22
|
|
58
23
|
def self.table_name
|
59
|
-
|
24
|
+
# Table name needs to be resolved lazily
|
25
|
+
# because RHS class might not have been loaded
|
26
|
+
@table_name ||= table_name_resolver.call
|
60
27
|
end
|
61
28
|
|
62
29
|
def self.compute_type(class_name)
|
@@ -79,14 +46,13 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
79
46
|
end
|
80
47
|
|
81
48
|
private
|
82
|
-
|
83
49
|
def self.suppress_composite_primary_key(pk)
|
84
50
|
pk unless pk.is_a?(Array)
|
85
51
|
end
|
86
52
|
}
|
87
53
|
|
88
54
|
join_model.name = "HABTM_#{association_name.to_s.camelize}"
|
89
|
-
join_model.table_name_resolver =
|
55
|
+
join_model.table_name_resolver = -> { table_name }
|
90
56
|
join_model.left_model = lhs_model
|
91
57
|
|
92
58
|
join_model.add_left_association :left_side, anonymous_class: lhs_model
|
@@ -96,7 +62,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
96
62
|
|
97
63
|
def middle_reflection(join_model)
|
98
64
|
middle_name = [lhs_model.name.downcase.pluralize,
|
99
|
-
association_name].join("_"
|
65
|
+
association_name.to_s].sort.join("_").gsub("::", "_").to_sym
|
100
66
|
middle_options = middle_options join_model
|
101
67
|
|
102
68
|
HasMany.create_reflection(lhs_model,
|
@@ -106,17 +72,27 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
106
72
|
end
|
107
73
|
|
108
74
|
private
|
109
|
-
|
110
75
|
def middle_options(join_model)
|
111
76
|
middle_options = {}
|
112
77
|
middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
|
113
|
-
middle_options[:source] = join_model.left_reflection.name
|
114
78
|
if options.key? :foreign_key
|
115
79
|
middle_options[:foreign_key] = options[:foreign_key]
|
116
80
|
end
|
117
81
|
middle_options
|
118
82
|
end
|
119
83
|
|
84
|
+
def table_name
|
85
|
+
if options[:join_table]
|
86
|
+
options[:join_table].to_s
|
87
|
+
else
|
88
|
+
class_name = options.fetch(:class_name) {
|
89
|
+
association_name.to_s.camelize.singularize
|
90
|
+
}
|
91
|
+
klass = lhs_model.send(:compute_type, class_name.to_s)
|
92
|
+
[lhs_model.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
120
96
|
def belongs_to_options(options)
|
121
97
|
rhs_options = {}
|
122
98
|
|
@@ -7,11 +7,17 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
super + [:
|
10
|
+
valid = super + [:counter_cache, :join_table, :index_errors, :ensuring_owner_was]
|
11
|
+
valid += [:as, :foreign_type] if options[:as]
|
12
|
+
valid += [:through, :source, :source_type] if options[:through]
|
13
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
14
|
+
valid
|
11
15
|
end
|
12
16
|
|
13
17
|
def self.valid_dependent_options
|
14
|
-
[:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception]
|
18
|
+
[:destroy, :delete_all, :nullify, :restrict_with_error, :restrict_with_exception, :destroy_async]
|
15
19
|
end
|
20
|
+
|
21
|
+
private_class_method :macro, :valid_options, :valid_dependent_options
|
16
22
|
end
|
17
23
|
end
|
@@ -7,13 +7,20 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.valid_options(options)
|
10
|
-
valid = super
|
10
|
+
valid = super
|
11
|
+
valid += [:as, :foreign_type] if options[:as]
|
12
|
+
valid += [:ensuring_owner_was] if options[:dependent] == :destroy_async
|
11
13
|
valid += [:through, :source, :source_type] if options[:through]
|
12
14
|
valid
|
13
15
|
end
|
14
16
|
|
15
17
|
def self.valid_dependent_options
|
16
|
-
[:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
|
18
|
+
[:destroy, :destroy_async, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.define_callbacks(model, reflection)
|
22
|
+
super
|
23
|
+
add_touch_callbacks(model, reflection) if reflection.options[:touch]
|
17
24
|
end
|
18
25
|
|
19
26
|
def self.add_destroy_callbacks(model, reflection)
|
@@ -26,5 +33,29 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
26
33
|
model.validates_presence_of reflection.name, message: :required
|
27
34
|
end
|
28
35
|
end
|
36
|
+
|
37
|
+
def self.touch_record(record, name, touch)
|
38
|
+
instance = record.send(name)
|
39
|
+
|
40
|
+
if instance&.persisted?
|
41
|
+
touch != true ?
|
42
|
+
instance.touch(touch) : instance.touch
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.add_touch_callbacks(model, reflection)
|
47
|
+
name = reflection.name
|
48
|
+
touch = reflection.options[:touch]
|
49
|
+
|
50
|
+
callback = -> (record) { HasOne.touch_record(record, name, touch) }
|
51
|
+
model.after_create callback, if: :saved_changes?
|
52
|
+
model.after_create_commit { association(name).reset_negative_cache }
|
53
|
+
model.after_update callback, if: :saved_changes?
|
54
|
+
model.after_destroy callback
|
55
|
+
model.after_touch callback
|
56
|
+
end
|
57
|
+
|
58
|
+
private_class_method :macro, :valid_options, :valid_dependent_options, :add_destroy_callbacks,
|
59
|
+
:define_callbacks, :define_validations, :add_touch_callbacks
|
29
60
|
end
|
30
61
|
end
|
@@ -5,7 +5,7 @@
|
|
5
5
|
module ActiveRecord::Associations::Builder # :nodoc:
|
6
6
|
class SingularAssociation < Association #:nodoc:
|
7
7
|
def self.valid_options(options)
|
8
|
-
super + [:
|
8
|
+
super + [:required, :touch]
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.define_accessors(model, reflection)
|
@@ -38,5 +38,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
38
38
|
end
|
39
39
|
CODE
|
40
40
|
end
|
41
|
+
|
42
|
+
private_class_method :valid_options, :define_accessors, :define_constructors
|
41
43
|
end
|
42
44
|
end
|
@@ -56,7 +56,7 @@ module ActiveRecord
|
|
56
56
|
def ids_writer(ids)
|
57
57
|
primary_key = reflection.association_primary_key
|
58
58
|
pk_type = klass.type_for_attribute(primary_key)
|
59
|
-
ids = Array(ids).
|
59
|
+
ids = Array(ids).compact_blank
|
60
60
|
ids.map! { |i| pk_type.cast(i) }
|
61
61
|
|
62
62
|
records = klass.where(primary_key => ids).index_by do |r|
|
@@ -101,11 +101,11 @@ module ActiveRecord
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
def build(attributes =
|
104
|
+
def build(attributes = nil, &block)
|
105
105
|
if attributes.is_a?(Array)
|
106
106
|
attributes.collect { |attr| build(attr, &block) }
|
107
107
|
else
|
108
|
-
add_to_target(build_record(attributes, &block))
|
108
|
+
add_to_target(build_record(attributes, &block), replace: true)
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
@@ -211,9 +211,11 @@ module ActiveRecord
|
|
211
211
|
def size
|
212
212
|
if !find_target? || loaded?
|
213
213
|
target.size
|
214
|
+
elsif @association_ids
|
215
|
+
@association_ids.size
|
214
216
|
elsif !association_scope.group_values.empty?
|
215
217
|
load_target.size
|
216
|
-
elsif !association_scope.distinct_value && target.
|
218
|
+
elsif !association_scope.distinct_value && !target.empty?
|
217
219
|
unsaved_records = target.select(&:new_record?)
|
218
220
|
unsaved_records.size + count_records
|
219
221
|
else
|
@@ -226,14 +228,14 @@ module ActiveRecord
|
|
226
228
|
# If the collection has been loaded
|
227
229
|
# it is equivalent to <tt>collection.size.zero?</tt>. If the
|
228
230
|
# collection has not been loaded, it is equivalent to
|
229
|
-
# <tt
|
231
|
+
# <tt>!collection.exists?</tt>. If the collection has not already been
|
230
232
|
# loaded and you are going to fetch the records anyway it is better to
|
231
233
|
# check <tt>collection.length.zero?</tt>.
|
232
234
|
def empty?
|
233
|
-
if loaded?
|
235
|
+
if loaded? || @association_ids || reflection.has_cached_counter?
|
234
236
|
size.zero?
|
235
237
|
else
|
236
|
-
|
238
|
+
target.empty? && !scope.exists?
|
237
239
|
end
|
238
240
|
end
|
239
241
|
|
@@ -276,13 +278,24 @@ module ActiveRecord
|
|
276
278
|
target
|
277
279
|
end
|
278
280
|
|
279
|
-
def add_to_target(record, skip_callbacks
|
280
|
-
if association_scope.distinct_value
|
281
|
+
def add_to_target(record, skip_callbacks: false, replace: false, &block)
|
282
|
+
if replace || association_scope.distinct_value
|
281
283
|
index = @target.index(record)
|
282
284
|
end
|
283
285
|
replace_on_target(record, index, skip_callbacks, &block)
|
284
286
|
end
|
285
287
|
|
288
|
+
def target=(record)
|
289
|
+
return super unless ActiveRecord::Base.has_many_inversing
|
290
|
+
|
291
|
+
case record
|
292
|
+
when Array
|
293
|
+
super
|
294
|
+
else
|
295
|
+
add_to_target(record, skip_callbacks: true, replace: true)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
286
299
|
def scope
|
287
300
|
scope = super
|
288
301
|
scope.none! if null_scope?
|
@@ -295,28 +308,13 @@ module ActiveRecord
|
|
295
308
|
|
296
309
|
def find_from_target?
|
297
310
|
loaded? ||
|
311
|
+
owner.strict_loading? ||
|
312
|
+
reflection.strict_loading? ||
|
298
313
|
owner.new_record? ||
|
299
314
|
target.any? { |record| record.new_record? || record.changed? }
|
300
315
|
end
|
301
316
|
|
302
317
|
private
|
303
|
-
|
304
|
-
def find_target
|
305
|
-
scope = self.scope
|
306
|
-
return scope.to_a if skip_statement_cache?(scope)
|
307
|
-
|
308
|
-
conn = klass.connection
|
309
|
-
sc = reflection.association_scope_cache(conn, owner) do |params|
|
310
|
-
as = AssociationScope.create { params.bind }
|
311
|
-
target_scope.merge!(as.scope(self))
|
312
|
-
end
|
313
|
-
|
314
|
-
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
315
|
-
sc.execute(binds, conn) do |record|
|
316
|
-
set_inverse_instance(record)
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
318
|
# We have some records loaded from the database (persisted) and some that are
|
321
319
|
# in-memory (memory). The same record may be represented in the persisted array
|
322
320
|
# and in the memory array.
|
@@ -393,10 +391,12 @@ module ActiveRecord
|
|
393
391
|
end
|
394
392
|
|
395
393
|
def remove_records(existing_records, records, method)
|
396
|
-
|
394
|
+
catch(:abort) do
|
395
|
+
records.each { |record| callback(:before_remove, record) }
|
396
|
+
end || return
|
397
397
|
|
398
398
|
delete_records(existing_records, method) if existing_records.any?
|
399
|
-
|
399
|
+
@target -= records
|
400
400
|
@association_ids = nil
|
401
401
|
|
402
402
|
records.each { |record| callback(:after_remove, record) }
|
@@ -449,7 +449,9 @@ module ActiveRecord
|
|
449
449
|
end
|
450
450
|
|
451
451
|
def replace_on_target(record, index, skip_callbacks)
|
452
|
-
|
452
|
+
catch(:abort) do
|
453
|
+
callback(:before_add, record)
|
454
|
+
end || return unless skip_callbacks
|
453
455
|
|
454
456
|
set_inverse_instance(record)
|
455
457
|
|