activerecord 5.1.7 → 5.2.8.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +629 -661
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/examples/performance.rb +2 -0
- data/examples/simple.rb +2 -0
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +41 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +27 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +4 -7
- data/lib/active_record/associations/builder/belongs_to.rb +12 -4
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +2 -0
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +59 -47
- data/lib/active_record/associations/collection_proxy.rb +20 -49
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +12 -1
- data/lib/active_record/associations/has_many_through_association.rb +36 -30
- data/lib/active_record/associations/has_one_association.rb +12 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
- data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
- data/lib/active_record/associations/join_dependency.rb +48 -93
- data/lib/active_record/associations/preloader/association.rb +45 -61
- data/lib/active_record/associations/preloader/through_association.rb +71 -79
- data/lib/active_record/associations/preloader.rb +18 -38
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +26 -11
- data/lib/active_record/associations.rb +40 -63
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +30 -214
- data/lib/active_record/attribute_methods/primary_key.rb +7 -6
- data/lib/active_record/attribute_methods/query.rb +2 -0
- data/lib/active_record/attribute_methods/read.rb +9 -3
- data/lib/active_record/attribute_methods/serialization.rb +23 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
- data/lib/active_record/attribute_methods/write.rb +21 -9
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attributes.rb +6 -5
- data/lib/active_record/autosave_association.rb +35 -19
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +8 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +15 -1
- data/lib/active_record/collection_cache_key.rb +12 -8
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
- data/lib/active_record/connection_adapters/column.rb +3 -1
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +233 -111
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
- data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +81 -94
- data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
- data/lib/active_record/connection_handling.rb +4 -2
- data/lib/active_record/core.rb +51 -61
- data/lib/active_record/counter_cache.rb +10 -3
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +18 -13
- data/lib/active_record/errors.rb +42 -3
- data/lib/active_record/explain.rb +3 -1
- data/lib/active_record/explain_registry.rb +2 -0
- data/lib/active_record/explain_subscriber.rb +2 -0
- data/lib/active_record/fixture_set/file.rb +2 -0
- data/lib/active_record/fixtures.rb +67 -60
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +49 -19
- data/lib/active_record/integration.rb +58 -19
- data/lib/active_record/internal_metadata.rb +2 -0
- data/lib/active_record/legacy_yaml_adapter.rb +3 -1
- data/lib/active_record/locking/optimistic.rb +14 -17
- data/lib/active_record/locking/pessimistic.rb +9 -6
- data/lib/active_record/log_subscriber.rb +43 -0
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +47 -9
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/model_schema.rb +16 -21
- data/lib/active_record/nested_attributes.rb +18 -6
- data/lib/active_record/no_touching.rb +3 -1
- data/lib/active_record/null_relation.rb +2 -0
- data/lib/active_record/persistence.rb +167 -16
- data/lib/active_record/query_cache.rb +6 -8
- data/lib/active_record/querying.rb +4 -2
- data/lib/active_record/railtie.rb +80 -6
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +46 -36
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +108 -194
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/batches.rb +20 -5
- data/lib/active_record/relation/calculations.rb +45 -19
- data/lib/active_record/relation/delegation.rb +45 -27
- data/lib/active_record/relation/finder_methods.rb +75 -76
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- data/lib/active_record/relation/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +128 -99
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -68
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- data/lib/active_record/relation.rb +120 -214
- data/lib/active_record/result.rb +2 -0
- data/lib/active_record/runtime_registry.rb +2 -0
- data/lib/active_record/sanitization.rb +129 -121
- data/lib/active_record/schema.rb +4 -2
- data/lib/active_record/schema_dumper.rb +36 -26
- data/lib/active_record/schema_migration.rb +2 -0
- data/lib/active_record/scoping/default.rb +8 -9
- data/lib/active_record/scoping/named.rb +23 -7
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/secure_token.rb +2 -0
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +23 -13
- data/lib/active_record/store.rb +3 -1
- data/lib/active_record/suppressor.rb +2 -0
- data/lib/active_record/table_metadata.rb +12 -3
- data/lib/active_record/tasks/database_tasks.rb +25 -14
- data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
- data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +33 -28
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +2 -0
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +2 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +2 -0
- data/lib/active_record/type/text.rb +2 -0
- data/lib/active_record/type/time.rb +2 -0
- data/lib/active_record/type/type_map.rb +2 -0
- data/lib/active_record/type/unsigned_integer.rb +2 -0
- data/lib/active_record/type.rb +4 -1
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -0
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +2 -0
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +2 -0
- data/lib/active_record/validations/uniqueness.rb +35 -5
- data/lib/active_record/validations.rb +2 -0
- data/lib/active_record/version.rb +2 -0
- data/lib/active_record.rb +11 -4
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +2 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +3 -1
- metadata +26 -39
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -15
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -18
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute.rb +0 -240
- data/lib/active_record/attribute_mutation_tracker.rb +0 -122
- data/lib/active_record/attribute_set/builder.rb +0 -126
- data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
- data/lib/active_record/attribute_set.rb +0 -113
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
- data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,22 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Belongs To Polymorphic Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Belongs To Polymorphic Association
|
4
6
|
class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc:
|
5
7
|
def klass
|
6
8
|
type = owner[reflection.foreign_type]
|
7
9
|
type.presence && type.constantize
|
8
10
|
end
|
9
11
|
|
10
|
-
|
12
|
+
def target_changed?
|
13
|
+
super || owner.saved_change_to_attribute?(reflection.foreign_type)
|
14
|
+
end
|
11
15
|
|
16
|
+
private
|
12
17
|
def replace_keys(record)
|
13
18
|
super
|
14
|
-
owner[reflection.foreign_type] = record.class.
|
15
|
-
end
|
16
|
-
|
17
|
-
def remove_keys
|
18
|
-
super
|
19
|
-
owner[reflection.foreign_type] = nil
|
19
|
+
owner[reflection.foreign_type] = record ? record.class.polymorphic_name : nil
|
20
20
|
end
|
21
21
|
|
22
22
|
def different_target?(record)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This is the parent Association class which defines the variables
|
2
4
|
# used by all associations.
|
3
5
|
#
|
@@ -36,11 +38,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
36
38
|
def self.create_reflection(model, name, scope, options, extension = nil)
|
37
39
|
raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
|
38
40
|
|
39
|
-
if scope.is_a?(Hash)
|
40
|
-
options = scope
|
41
|
-
scope = nil
|
42
|
-
end
|
43
|
-
|
44
41
|
validate_options(options)
|
45
42
|
|
46
43
|
scope = build_scope(scope, extension)
|
@@ -107,8 +104,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
107
104
|
|
108
105
|
def self.define_readers(mixin, name)
|
109
106
|
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
110
|
-
def #{name}
|
111
|
-
association(:#{name}).reader
|
107
|
+
def #{name}
|
108
|
+
association(:#{name}).reader
|
112
109
|
end
|
113
110
|
CODE
|
114
111
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord::Associations::Builder # :nodoc:
|
2
4
|
class BelongsTo < SingularAssociation #:nodoc:
|
3
5
|
def self.macro
|
@@ -32,11 +34,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
32
34
|
foreign_key = reflection.foreign_key
|
33
35
|
cache_column = reflection.counter_cache_column
|
34
36
|
|
35
|
-
if (@
|
36
|
-
@_after_create_counter_called = false
|
37
|
-
elsif (@_after_replace_counter_called ||= false)
|
37
|
+
if (@_after_replace_counter_called ||= false)
|
38
38
|
@_after_replace_counter_called = false
|
39
|
-
elsif
|
39
|
+
elsif association(reflection.name).target_changed?
|
40
40
|
if reflection.polymorphic?
|
41
41
|
model = attribute_in_database(reflection.foreign_type).try(:constantize)
|
42
42
|
model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
|
@@ -49,14 +49,22 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
49
49
|
foreign_key = attribute_in_database foreign_key
|
50
50
|
|
51
51
|
if foreign_key && model.respond_to?(:increment_counter)
|
52
|
+
foreign_key = counter_cache_target(reflection, model, foreign_key)
|
52
53
|
model.increment_counter(cache_column, foreign_key)
|
53
54
|
end
|
54
55
|
|
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)
|
56
58
|
model_was.decrement_counter(cache_column, foreign_key_was)
|
57
59
|
end
|
58
60
|
end
|
59
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
|
60
68
|
end
|
61
69
|
end
|
62
70
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_record/associations"
|
4
4
|
|
@@ -20,10 +20,10 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.define_extensions(model, name)
|
23
|
+
def self.define_extensions(model, name, &block)
|
24
24
|
if block_given?
|
25
25
|
extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
|
26
|
-
extension = Module.new(&
|
26
|
+
extension = Module.new(&block)
|
27
27
|
model.parent.const_set(extension_module_name, extension)
|
28
28
|
end
|
29
29
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord::Associations::Builder # :nodoc:
|
2
4
|
class HasAndBelongsToMany # :nodoc:
|
3
5
|
class JoinTableResolver # :nodoc:
|
@@ -45,7 +47,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
45
47
|
habtm = JoinTableResolver.build lhs_model, association_name, options
|
46
48
|
|
47
49
|
join_model = Class.new(ActiveRecord::Base) {
|
48
|
-
class << self
|
50
|
+
class << self
|
49
51
|
attr_accessor :left_model
|
50
52
|
attr_accessor :name
|
51
53
|
attr_accessor :table_name_resolver
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
# = Active Record Association Collection
|
@@ -43,6 +45,8 @@ module ActiveRecord
|
|
43
45
|
def ids_reader
|
44
46
|
if loaded?
|
45
47
|
target.pluck(reflection.association_primary_key)
|
48
|
+
elsif !target.empty?
|
49
|
+
load_target.pluck(reflection.association_primary_key)
|
46
50
|
else
|
47
51
|
@association_ids ||= scope.pluck(reflection.association_primary_key)
|
48
52
|
end
|
@@ -50,17 +54,19 @@ module ActiveRecord
|
|
50
54
|
|
51
55
|
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
|
52
56
|
def ids_writer(ids)
|
53
|
-
|
57
|
+
primary_key = reflection.association_primary_key
|
58
|
+
pk_type = klass.type_for_attribute(primary_key)
|
54
59
|
ids = Array(ids).reject(&:blank?)
|
55
60
|
ids.map! { |i| pk_type.cast(i) }
|
56
61
|
|
57
|
-
primary_key = reflection.association_primary_key
|
58
62
|
records = klass.where(primary_key => ids).index_by do |r|
|
59
63
|
r.public_send(primary_key)
|
60
64
|
end.values_at(*ids).compact
|
61
65
|
|
62
66
|
if records.size != ids.size
|
63
|
-
|
67
|
+
found_ids = records.map { |record| record.public_send(primary_key) }
|
68
|
+
not_found_ids = ids - found_ids
|
69
|
+
klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids)
|
64
70
|
else
|
65
71
|
replace(records)
|
66
72
|
end
|
@@ -69,26 +75,29 @@ module ActiveRecord
|
|
69
75
|
def reset
|
70
76
|
super
|
71
77
|
@target = []
|
78
|
+
@association_ids = nil
|
72
79
|
end
|
73
80
|
|
74
81
|
def find(*args)
|
75
|
-
if
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
82
|
+
if options[:inverse_of] && loaded?
|
83
|
+
args_flatten = args.flatten
|
84
|
+
model = scope.klass
|
85
|
+
|
86
|
+
if args_flatten.blank?
|
87
|
+
error_message = "Couldn't find #{model.name} without an ID"
|
88
|
+
raise RecordNotFound.new(error_message, model.name, model.primary_key, args)
|
89
|
+
end
|
90
|
+
|
91
|
+
result = find_by_scan(*args)
|
92
|
+
|
93
|
+
result_size = Array(result).size
|
94
|
+
if !result || result_size != args_flatten.size
|
95
|
+
scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
|
89
96
|
else
|
90
|
-
|
97
|
+
result
|
91
98
|
end
|
99
|
+
else
|
100
|
+
scope.find(*args)
|
92
101
|
end
|
93
102
|
end
|
94
103
|
|
@@ -96,15 +105,12 @@ module ActiveRecord
|
|
96
105
|
if attributes.is_a?(Array)
|
97
106
|
attributes.collect { |attr| build(attr, &block) }
|
98
107
|
else
|
99
|
-
add_to_target(build_record(attributes))
|
100
|
-
yield(record) if block_given?
|
101
|
-
end
|
108
|
+
add_to_target(build_record(attributes, &block))
|
102
109
|
end
|
103
110
|
end
|
104
111
|
|
105
|
-
# Add +records+ to this association.
|
106
|
-
#
|
107
|
-
# +push+ and +concat+ behave identically.
|
112
|
+
# Add +records+ to this association. Since +<<+ flattens its argument list
|
113
|
+
# and inserts each record, +push+ and +concat+ behave identically.
|
108
114
|
def concat(*records)
|
109
115
|
records = records.flatten
|
110
116
|
if owner.new_record?
|
@@ -180,8 +186,6 @@ module ActiveRecord
|
|
180
186
|
# are actually removed from the database, that depends precisely on
|
181
187
|
# +delete_records+. They are in any case removed from the collection.
|
182
188
|
def delete(*records)
|
183
|
-
return if records.empty?
|
184
|
-
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
|
185
189
|
delete_or_destroy(records, options[:dependent])
|
186
190
|
end
|
187
191
|
|
@@ -191,8 +195,6 @@ module ActiveRecord
|
|
191
195
|
# Note that this method removes records from the database ignoring the
|
192
196
|
# +:dependent+ option.
|
193
197
|
def destroy(*records)
|
194
|
-
return if records.empty?
|
195
|
-
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
|
196
198
|
delete_or_destroy(records, :destroy)
|
197
199
|
end
|
198
200
|
|
@@ -300,18 +302,17 @@ module ActiveRecord
|
|
300
302
|
private
|
301
303
|
|
302
304
|
def find_target
|
303
|
-
|
305
|
+
scope = self.scope
|
306
|
+
return scope.to_a if skip_statement_cache?(scope)
|
304
307
|
|
305
308
|
conn = klass.connection
|
306
|
-
sc = reflection.association_scope_cache(conn, owner) do
|
307
|
-
|
308
|
-
|
309
|
-
target_scope.merge as.scope(self, conn)
|
310
|
-
}
|
309
|
+
sc = reflection.association_scope_cache(conn, owner) do |params|
|
310
|
+
as = AssociationScope.create { params.bind }
|
311
|
+
target_scope.merge!(as.scope(self))
|
311
312
|
end
|
312
313
|
|
313
314
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
314
|
-
sc.execute(binds,
|
315
|
+
sc.execute(binds, conn) do |record|
|
315
316
|
set_inverse_instance(record)
|
316
317
|
end
|
317
318
|
end
|
@@ -354,12 +355,17 @@ module ActiveRecord
|
|
354
355
|
if attributes.is_a?(Array)
|
355
356
|
attributes.collect { |attr| _create_record(attr, raise, &block) }
|
356
357
|
else
|
358
|
+
record = build_record(attributes, &block)
|
357
359
|
transaction do
|
358
|
-
|
359
|
-
|
360
|
-
insert_record(record, true, raise) {
|
360
|
+
result = nil
|
361
|
+
add_to_target(record) do
|
362
|
+
result = insert_record(record, true, raise) {
|
363
|
+
@_was_loaded = loaded?
|
364
|
+
}
|
361
365
|
end
|
366
|
+
raise ActiveRecord::Rollback unless result
|
362
367
|
end
|
368
|
+
record
|
363
369
|
end
|
364
370
|
end
|
365
371
|
|
@@ -372,11 +378,9 @@ module ActiveRecord
|
|
372
378
|
end
|
373
379
|
end
|
374
380
|
|
375
|
-
def create_scope
|
376
|
-
scope.scope_for_create.stringify_keys
|
377
|
-
end
|
378
|
-
|
379
381
|
def delete_or_destroy(records, method)
|
382
|
+
return if records.empty?
|
383
|
+
records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
|
380
384
|
records = records.flatten
|
381
385
|
records.each { |record| raise_on_type_mismatch!(record) }
|
382
386
|
existing_records = records.reject(&:new_record?)
|
@@ -393,6 +397,7 @@ module ActiveRecord
|
|
393
397
|
|
394
398
|
delete_records(existing_records, method) if existing_records.any?
|
395
399
|
records.each { |record| target.delete(record) }
|
400
|
+
@association_ids = nil
|
396
401
|
|
397
402
|
records.each { |record| callback(:after_remove, record) }
|
398
403
|
end
|
@@ -405,9 +410,9 @@ module ActiveRecord
|
|
405
410
|
end
|
406
411
|
|
407
412
|
def replace_records(new_target, original_target)
|
408
|
-
delete(target
|
413
|
+
delete(difference(target, new_target))
|
409
414
|
|
410
|
-
unless concat(new_target
|
415
|
+
unless concat(difference(new_target, target))
|
411
416
|
@target = original_target
|
412
417
|
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
|
413
418
|
"new records could not be saved."
|
@@ -417,7 +422,7 @@ module ActiveRecord
|
|
417
422
|
end
|
418
423
|
|
419
424
|
def replace_common_records_in_memory(new_target, original_target)
|
420
|
-
common_records = new_target
|
425
|
+
common_records = intersection(new_target, original_target)
|
421
426
|
common_records.each do |record|
|
422
427
|
skip_callbacks = true
|
423
428
|
replace_on_target(record, @target.index(record), skip_callbacks)
|
@@ -430,11 +435,17 @@ module ActiveRecord
|
|
430
435
|
records.each do |record|
|
431
436
|
raise_on_type_mismatch!(record)
|
432
437
|
add_to_target(record) do
|
433
|
-
|
438
|
+
unless owner.new_record?
|
439
|
+
result &&= insert_record(record, true, raise) {
|
440
|
+
@_was_loaded = loaded?
|
441
|
+
}
|
442
|
+
end
|
434
443
|
end
|
435
444
|
end
|
436
445
|
|
437
|
-
|
446
|
+
raise ActiveRecord::Rollback unless result
|
447
|
+
|
448
|
+
records
|
438
449
|
end
|
439
450
|
|
440
451
|
def replace_on_target(record, index, skip_callbacks)
|
@@ -449,6 +460,7 @@ module ActiveRecord
|
|
449
460
|
if index
|
450
461
|
target[index] = record
|
451
462
|
elsif @_was_loaded || !loaded?
|
463
|
+
@association_ids = nil
|
452
464
|
target << record
|
453
465
|
end
|
454
466
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
# Association proxies in Active Record are middlemen between the object that
|
@@ -30,7 +32,7 @@ module ActiveRecord
|
|
30
32
|
class CollectionProxy < Relation
|
31
33
|
def initialize(klass, association) #:nodoc:
|
32
34
|
@association = association
|
33
|
-
super klass
|
35
|
+
super klass
|
34
36
|
|
35
37
|
extensions = association.extensions
|
36
38
|
extend(*extensions) if extensions.any?
|
@@ -133,8 +135,9 @@ module ActiveRecord
|
|
133
135
|
# # #<Pet id: 2, name: "Spook", person_id: 1>,
|
134
136
|
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
|
135
137
|
# # ]
|
136
|
-
def find(*args
|
137
|
-
|
138
|
+
def find(*args)
|
139
|
+
return super if block_given?
|
140
|
+
@association.find(*args)
|
138
141
|
end
|
139
142
|
|
140
143
|
##
|
@@ -363,34 +366,6 @@ module ActiveRecord
|
|
363
366
|
@association.create!(attributes, &block)
|
364
367
|
end
|
365
368
|
|
366
|
-
# Add one or more records to the collection by setting their foreign keys
|
367
|
-
# to the association's primary key. Since #<< flattens its argument list and
|
368
|
-
# inserts each record, +push+ and #concat behave identically. Returns +self+
|
369
|
-
# so method calls may be chained.
|
370
|
-
#
|
371
|
-
# class Person < ActiveRecord::Base
|
372
|
-
# has_many :pets
|
373
|
-
# end
|
374
|
-
#
|
375
|
-
# person.pets.size # => 0
|
376
|
-
# person.pets.concat(Pet.new(name: 'Fancy-Fancy'))
|
377
|
-
# person.pets.concat(Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo'))
|
378
|
-
# person.pets.size # => 3
|
379
|
-
#
|
380
|
-
# person.id # => 1
|
381
|
-
# person.pets
|
382
|
-
# # => [
|
383
|
-
# # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
|
384
|
-
# # #<Pet id: 2, name: "Spook", person_id: 1>,
|
385
|
-
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
|
386
|
-
# # ]
|
387
|
-
#
|
388
|
-
# person.pets.concat([Pet.new(name: 'Brain'), Pet.new(name: 'Benny')])
|
389
|
-
# person.pets.size # => 5
|
390
|
-
def concat(*records)
|
391
|
-
@association.concat(*records)
|
392
|
-
end
|
393
|
-
|
394
369
|
# Replaces this collection with +other_array+. This will perform a diff
|
395
370
|
# and delete/add only records that have changed.
|
396
371
|
#
|
@@ -497,7 +472,7 @@ module ActiveRecord
|
|
497
472
|
# Pet.find(1, 2, 3)
|
498
473
|
# # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)
|
499
474
|
def delete_all(dependent = nil)
|
500
|
-
@association.delete_all(dependent)
|
475
|
+
@association.delete_all(dependent).tap { reset_scope }
|
501
476
|
end
|
502
477
|
|
503
478
|
# Deletes the records of the collection directly from the database
|
@@ -524,7 +499,7 @@ module ActiveRecord
|
|
524
499
|
#
|
525
500
|
# Pet.find(1) # => Couldn't find Pet with id=1
|
526
501
|
def destroy_all
|
527
|
-
@association.destroy_all
|
502
|
+
@association.destroy_all.tap { reset_scope }
|
528
503
|
end
|
529
504
|
|
530
505
|
# Deletes the +records+ supplied from the collection according to the strategy
|
@@ -643,7 +618,7 @@ module ActiveRecord
|
|
643
618
|
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
|
644
619
|
# # ]
|
645
620
|
def delete(*records)
|
646
|
-
@association.delete(*records)
|
621
|
+
@association.delete(*records).tap { reset_scope }
|
647
622
|
end
|
648
623
|
|
649
624
|
# Destroys the +records+ supplied and removes them from the collection.
|
@@ -715,7 +690,7 @@ module ActiveRecord
|
|
715
690
|
#
|
716
691
|
# Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (4, 5, 6)
|
717
692
|
def destroy(*records)
|
718
|
-
@association.destroy(*records)
|
693
|
+
@association.destroy(*records).tap { reset_scope }
|
719
694
|
end
|
720
695
|
|
721
696
|
##
|
@@ -746,10 +721,6 @@ module ActiveRecord
|
|
746
721
|
# # ]
|
747
722
|
|
748
723
|
#--
|
749
|
-
def uniq
|
750
|
-
load_target.uniq
|
751
|
-
end
|
752
|
-
|
753
724
|
def calculate(operation, column_name)
|
754
725
|
null_scope? ? scope.calculate(operation, column_name) : super
|
755
726
|
end
|
@@ -989,6 +960,12 @@ module ActiveRecord
|
|
989
960
|
load_target == other
|
990
961
|
end
|
991
962
|
|
963
|
+
##
|
964
|
+
# :method: to_ary
|
965
|
+
#
|
966
|
+
# :call-seq:
|
967
|
+
# to_ary()
|
968
|
+
#
|
992
969
|
# Returns a new array of objects from the collection. If the collection
|
993
970
|
# hasn't been loaded, it fetches the records from the database.
|
994
971
|
#
|
@@ -1022,18 +999,15 @@ module ActiveRecord
|
|
1022
999
|
# # #<Pet id: 5, name: "Brain", person_id: 1>,
|
1023
1000
|
# # #<Pet id: 6, name: "Boss", person_id: 1>
|
1024
1001
|
# # ]
|
1025
|
-
def to_ary
|
1026
|
-
load_target.dup
|
1027
|
-
end
|
1028
|
-
alias_method :to_a, :to_ary
|
1029
1002
|
|
1030
1003
|
def records # :nodoc:
|
1031
1004
|
load_target
|
1032
1005
|
end
|
1033
1006
|
|
1034
1007
|
# Adds one or more +records+ to the collection by setting their foreign keys
|
1035
|
-
# to the association's primary key.
|
1036
|
-
#
|
1008
|
+
# to the association's primary key. Since +<<+ flattens its argument list and
|
1009
|
+
# inserts each record, +push+ and +concat+ behave identically. Returns +self+
|
1010
|
+
# so several appends may be chained together.
|
1037
1011
|
#
|
1038
1012
|
# class Person < ActiveRecord::Base
|
1039
1013
|
# has_many :pets
|
@@ -1056,6 +1030,7 @@ module ActiveRecord
|
|
1056
1030
|
end
|
1057
1031
|
alias_method :push, :<<
|
1058
1032
|
alias_method :append, :<<
|
1033
|
+
alias_method :concat, :<<
|
1059
1034
|
|
1060
1035
|
def prepend(*args)
|
1061
1036
|
raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
|
@@ -1073,7 +1048,6 @@ module ActiveRecord
|
|
1073
1048
|
end
|
1074
1049
|
|
1075
1050
|
# Reloads the collection from the database. Returns +self+.
|
1076
|
-
# Equivalent to <tt>collection(true)</tt>.
|
1077
1051
|
#
|
1078
1052
|
# class Person < ActiveRecord::Base
|
1079
1053
|
# has_many :pets
|
@@ -1087,9 +1061,6 @@ module ActiveRecord
|
|
1087
1061
|
#
|
1088
1062
|
# person.pets.reload # fetches pets from the database
|
1089
1063
|
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
|
1090
|
-
#
|
1091
|
-
# person.pets(true) # fetches pets from the database
|
1092
|
-
# # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
|
1093
1064
|
def reload
|
1094
1065
|
proxy_association.reload
|
1095
1066
|
reset_scope
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has Many Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has Many Association
|
4
6
|
# This is the proxy that handles a has many association.
|
5
7
|
#
|
6
8
|
# If the association has a <tt>:through</tt> option further specialization
|
@@ -97,6 +99,7 @@ module ActiveRecord
|
|
97
99
|
def delete_or_nullify_all_records(method)
|
98
100
|
count = delete_count(method, scope)
|
99
101
|
update_counter(-count)
|
102
|
+
count
|
100
103
|
end
|
101
104
|
|
102
105
|
# Deletes the records according to the <tt>:dependent</tt> option.
|
@@ -128,6 +131,14 @@ module ActiveRecord
|
|
128
131
|
end
|
129
132
|
saved_successfully
|
130
133
|
end
|
134
|
+
|
135
|
+
def difference(a, b)
|
136
|
+
a - b
|
137
|
+
end
|
138
|
+
|
139
|
+
def intersection(a, b)
|
140
|
+
a & b
|
141
|
+
end
|
131
142
|
end
|
132
143
|
end
|
133
144
|
end
|