activerecord 5.1.5 → 5.2.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 +450 -699
- 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 +4 -2
- data/lib/active_record/associations/alias_tracker.rb +19 -27
- data/lib/active_record/associations/association.rb +33 -37
- data/lib/active_record/associations/association_scope.rb +38 -50
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- 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 +14 -5
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- 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 +52 -41
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +3 -1
- data/lib/active_record/associations/has_many_through_association.rb +8 -19
- 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 +22 -67
- 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 +17 -37
- 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 +25 -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 +7 -6
- data/lib/active_record/autosave_association.rb +16 -14
- data/lib/active_record/base.rb +2 -0
- data/lib/active_record/callbacks.rb +12 -6
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +2 -0
- data/lib/active_record/collection_cache_key.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
- 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 +149 -78
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
- 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 +2 -0
- 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 +6 -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 +3 -1
- 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 +3 -1
- 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 +8 -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 +14 -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 +248 -112
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
- 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 +20 -1
- 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 +79 -92
- 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 +39 -60
- data/lib/active_record/counter_cache.rb +20 -15
- data/lib/active_record/define_callbacks.rb +5 -3
- data/lib/active_record/dynamic_matchers.rb +9 -9
- data/lib/active_record/enum.rb +17 -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 +4 -2
- 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 +30 -42
- 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 +40 -2
- 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 +19 -24
- 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 +196 -48
- data/lib/active_record/query_cache.rb +12 -14
- data/lib/active_record/querying.rb +3 -1
- data/lib/active_record/railtie.rb +61 -3
- 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 +110 -192
- 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 +31 -9
- data/lib/active_record/relation/delegation.rb +15 -27
- data/lib/active_record/relation/finder_methods.rb +71 -76
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +47 -20
- 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 +55 -79
- data/lib/active_record/relation/query_attribute.rb +26 -2
- data/lib/active_record/relation/query_methods.rb +95 -91
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -1
- 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 +106 -219
- 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 +6 -7
- data/lib/active_record/scoping/named.rb +21 -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 +22 -12
- 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 +13 -6
- data/lib/active_record/touch_later.rb +2 -0
- data/lib/active_record/transactions.rb +32 -27
- 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 +6 -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 +36 -6
- 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 +23 -36
- 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 -114
- data/lib/active_record/attribute_set/builder.rb +0 -124
- 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,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
|
|
@@ -84,7 +92,8 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
84
92
|
else
|
85
93
|
klass = association.klass
|
86
94
|
end
|
87
|
-
|
95
|
+
primary_key = reflection.association_primary_key(klass)
|
96
|
+
old_record = klass.find_by(primary_key => old_foreign_id)
|
88
97
|
|
89
98
|
if old_record
|
90
99
|
if touch != true
|
@@ -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
|
@@ -50,17 +52,19 @@ module ActiveRecord
|
|
50
52
|
|
51
53
|
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
|
52
54
|
def ids_writer(ids)
|
53
|
-
|
55
|
+
primary_key = reflection.association_primary_key
|
56
|
+
pk_type = klass.type_for_attribute(primary_key)
|
54
57
|
ids = Array(ids).reject(&:blank?)
|
55
58
|
ids.map! { |i| pk_type.cast(i) }
|
56
59
|
|
57
|
-
primary_key = reflection.association_primary_key
|
58
60
|
records = klass.where(primary_key => ids).index_by do |r|
|
59
61
|
r.public_send(primary_key)
|
60
62
|
end.values_at(*ids).compact
|
61
63
|
|
62
64
|
if records.size != ids.size
|
63
|
-
|
65
|
+
found_ids = records.map { |record| record.public_send(primary_key) }
|
66
|
+
not_found_ids = ids - found_ids
|
67
|
+
klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids)
|
64
68
|
else
|
65
69
|
replace(records)
|
66
70
|
end
|
@@ -69,26 +73,29 @@ module ActiveRecord
|
|
69
73
|
def reset
|
70
74
|
super
|
71
75
|
@target = []
|
76
|
+
@association_ids = nil
|
72
77
|
end
|
73
78
|
|
74
79
|
def find(*args)
|
75
|
-
if
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
80
|
+
if options[:inverse_of] && loaded?
|
81
|
+
args_flatten = args.flatten
|
82
|
+
model = scope.klass
|
83
|
+
|
84
|
+
if args_flatten.blank?
|
85
|
+
error_message = "Couldn't find #{model.name} without an ID"
|
86
|
+
raise RecordNotFound.new(error_message, model.name, model.primary_key, args)
|
87
|
+
end
|
88
|
+
|
89
|
+
result = find_by_scan(*args)
|
90
|
+
|
91
|
+
result_size = Array(result).size
|
92
|
+
if !result || result_size != args_flatten.size
|
93
|
+
scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
|
89
94
|
else
|
90
|
-
|
95
|
+
result
|
91
96
|
end
|
97
|
+
else
|
98
|
+
scope.find(*args)
|
92
99
|
end
|
93
100
|
end
|
94
101
|
|
@@ -96,9 +103,7 @@ module ActiveRecord
|
|
96
103
|
if attributes.is_a?(Array)
|
97
104
|
attributes.collect { |attr| build(attr, &block) }
|
98
105
|
else
|
99
|
-
add_to_target(build_record(attributes))
|
100
|
-
yield(record) if block_given?
|
101
|
-
end
|
106
|
+
add_to_target(build_record(attributes, &block))
|
102
107
|
end
|
103
108
|
end
|
104
109
|
|
@@ -180,8 +185,6 @@ module ActiveRecord
|
|
180
185
|
# are actually removed from the database, that depends precisely on
|
181
186
|
# +delete_records+. They are in any case removed from the collection.
|
182
187
|
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
188
|
delete_or_destroy(records, options[:dependent])
|
186
189
|
end
|
187
190
|
|
@@ -191,8 +194,6 @@ module ActiveRecord
|
|
191
194
|
# Note that this method removes records from the database ignoring the
|
192
195
|
# +:dependent+ option.
|
193
196
|
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
197
|
delete_or_destroy(records, :destroy)
|
197
198
|
end
|
198
199
|
|
@@ -300,18 +301,17 @@ module ActiveRecord
|
|
300
301
|
private
|
301
302
|
|
302
303
|
def find_target
|
303
|
-
|
304
|
+
scope = self.scope
|
305
|
+
return scope.to_a if skip_statement_cache?(scope)
|
304
306
|
|
305
307
|
conn = klass.connection
|
306
|
-
sc = reflection.association_scope_cache(conn, owner) do
|
307
|
-
|
308
|
-
|
309
|
-
target_scope.merge as.scope(self, conn)
|
310
|
-
}
|
308
|
+
sc = reflection.association_scope_cache(conn, owner) do |params|
|
309
|
+
as = AssociationScope.create { params.bind }
|
310
|
+
target_scope.merge!(as.scope(self))
|
311
311
|
end
|
312
312
|
|
313
313
|
binds = AssociationScope.get_bind_values(owner, reflection.chain)
|
314
|
-
sc.execute(binds,
|
314
|
+
sc.execute(binds, conn) do |record|
|
315
315
|
set_inverse_instance(record)
|
316
316
|
end
|
317
317
|
end
|
@@ -354,12 +354,18 @@ module ActiveRecord
|
|
354
354
|
if attributes.is_a?(Array)
|
355
355
|
attributes.collect { |attr| _create_record(attr, raise, &block) }
|
356
356
|
else
|
357
|
+
record = build_record(attributes, &block)
|
357
358
|
transaction do
|
358
|
-
|
359
|
-
|
360
|
-
insert_record(record, true, raise) {
|
359
|
+
result = nil
|
360
|
+
add_to_target(record) do
|
361
|
+
result = insert_record(record, true, raise) {
|
362
|
+
@_was_loaded = loaded?
|
363
|
+
@association_ids = nil
|
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?)
|
@@ -430,11 +434,18 @@ module ActiveRecord
|
|
430
434
|
records.each do |record|
|
431
435
|
raise_on_type_mismatch!(record)
|
432
436
|
add_to_target(record) do
|
433
|
-
|
437
|
+
unless owner.new_record?
|
438
|
+
result &&= insert_record(record, true, raise) {
|
439
|
+
@_was_loaded = loaded?
|
440
|
+
@association_ids = nil
|
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)
|
@@ -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
|
##
|
@@ -746,10 +749,6 @@ module ActiveRecord
|
|
746
749
|
# # ]
|
747
750
|
|
748
751
|
#--
|
749
|
-
def uniq
|
750
|
-
load_target.uniq
|
751
|
-
end
|
752
|
-
|
753
752
|
def calculate(operation, column_name)
|
754
753
|
null_scope? ? scope.calculate(operation, column_name) : super
|
755
754
|
end
|
@@ -989,6 +988,12 @@ module ActiveRecord
|
|
989
988
|
load_target == other
|
990
989
|
end
|
991
990
|
|
991
|
+
##
|
992
|
+
# :method: to_ary
|
993
|
+
#
|
994
|
+
# :call-seq:
|
995
|
+
# to_ary()
|
996
|
+
#
|
992
997
|
# Returns a new array of objects from the collection. If the collection
|
993
998
|
# hasn't been loaded, it fetches the records from the database.
|
994
999
|
#
|
@@ -1022,10 +1027,6 @@ module ActiveRecord
|
|
1022
1027
|
# # #<Pet id: 5, name: "Brain", person_id: 1>,
|
1023
1028
|
# # #<Pet id: 6, name: "Boss", person_id: 1>
|
1024
1029
|
# # ]
|
1025
|
-
def to_ary
|
1026
|
-
load_target.dup
|
1027
|
-
end
|
1028
|
-
alias_method :to_a, :to_ary
|
1029
1030
|
|
1030
1031
|
def records # :nodoc:
|
1031
1032
|
load_target
|
@@ -1073,7 +1074,6 @@ module ActiveRecord
|
|
1073
1074
|
end
|
1074
1075
|
|
1075
1076
|
# Reloads the collection from the database. Returns +self+.
|
1076
|
-
# Equivalent to <tt>collection(true)</tt>.
|
1077
1077
|
#
|
1078
1078
|
# class Person < ActiveRecord::Base
|
1079
1079
|
# has_many :pets
|
@@ -1087,9 +1087,6 @@ module ActiveRecord
|
|
1087
1087
|
#
|
1088
1088
|
# person.pets.reload # fetches pets from the database
|
1089
1089
|
# # => [#<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
1090
|
def reload
|
1094
1091
|
proxy_association.reload
|
1095
1092
|
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
|
@@ -1,14 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has Many Through Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has Many Through Association
|
4
6
|
class HasManyThroughAssociation < HasManyAssociation #:nodoc:
|
5
7
|
include ThroughAssociation
|
6
8
|
|
7
9
|
def initialize(owner, reflection)
|
8
10
|
super
|
9
|
-
|
10
|
-
@through_records = {}
|
11
|
-
@through_association = nil
|
11
|
+
@through_records = {}
|
12
12
|
end
|
13
13
|
|
14
14
|
def concat(*records)
|
@@ -48,11 +48,6 @@ module ActiveRecord
|
|
48
48
|
end
|
49
49
|
|
50
50
|
private
|
51
|
-
|
52
|
-
def through_association
|
53
|
-
@through_association ||= owner.association(through_reflection.name)
|
54
|
-
end
|
55
|
-
|
56
51
|
# The through record (built with build_record) is temporarily cached
|
57
52
|
# so that it may be reused if insert_record is subsequently called.
|
58
53
|
#
|
@@ -95,7 +90,7 @@ module ActiveRecord
|
|
95
90
|
def build_record(attributes)
|
96
91
|
ensure_not_nested
|
97
92
|
|
98
|
-
record = super
|
93
|
+
record = super
|
99
94
|
|
100
95
|
inverse = source_reflection.inverse_of
|
101
96
|
if inverse
|
@@ -138,21 +133,15 @@ module ActiveRecord
|
|
138
133
|
|
139
134
|
scope = through_association.scope
|
140
135
|
scope.where! construct_join_attributes(*records)
|
136
|
+
scope = scope.where(through_scope_attributes)
|
141
137
|
|
142
138
|
case method
|
143
139
|
when :destroy
|
144
140
|
if scope.klass.primary_key
|
145
|
-
count = scope.destroy_all.
|
141
|
+
count = scope.destroy_all.count(&:destroyed?)
|
146
142
|
else
|
147
143
|
scope.each(&:_run_destroy_callbacks)
|
148
|
-
|
149
|
-
arel = scope.arel
|
150
|
-
|
151
|
-
stmt = Arel::DeleteManager.new
|
152
|
-
stmt.from scope.klass.arel_table
|
153
|
-
stmt.wheres = arel.constraints
|
154
|
-
|
155
|
-
count = scope.klass.connection.delete(stmt, "SQL", scope.bound_attributes)
|
144
|
+
count = scope.delete_all
|
156
145
|
end
|
157
146
|
when :nullify
|
158
147
|
count = scope.update_all(source_reflection.foreign_key => nil)
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has One Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has One Association
|
4
6
|
class HasOneAssociation < SingularAssociation #:nodoc:
|
5
7
|
include ForeignAssociation
|
6
8
|
|
@@ -58,6 +60,7 @@ module ActiveRecord
|
|
58
60
|
when :destroy
|
59
61
|
target.destroyed_by_association = reflection
|
60
62
|
target.destroy
|
63
|
+
throw(:abort) unless target.destroyed?
|
61
64
|
when :nullify
|
62
65
|
target.update_columns(reflection.foreign_key => nil) if target.persisted?
|
63
66
|
end
|
@@ -104,6 +107,14 @@ module ActiveRecord
|
|
104
107
|
yield
|
105
108
|
end
|
106
109
|
end
|
110
|
+
|
111
|
+
def _create_record(attributes, raise_error = false, &block)
|
112
|
+
unless owner.persisted?
|
113
|
+
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
|
114
|
+
end
|
115
|
+
|
116
|
+
super
|
117
|
+
end
|
107
118
|
end
|
108
119
|
end
|
109
120
|
end
|
@@ -1,20 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Has One Through Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Has One Through Association
|
4
6
|
class HasOneThroughAssociation < HasOneAssociation #:nodoc:
|
5
7
|
include ThroughAssociation
|
6
8
|
|
7
|
-
def replace(record)
|
8
|
-
create_through_record(record)
|
9
|
+
def replace(record, save = true)
|
10
|
+
create_through_record(record, save)
|
9
11
|
self.target = record
|
10
12
|
end
|
11
13
|
|
12
14
|
private
|
13
|
-
|
14
|
-
def create_through_record(record)
|
15
|
+
def create_through_record(record, save)
|
15
16
|
ensure_not_nested
|
16
17
|
|
17
|
-
through_proxy =
|
18
|
+
through_proxy = through_association
|
18
19
|
through_record = through_proxy.load_target
|
19
20
|
|
20
21
|
if through_record && !record
|
@@ -27,8 +28,12 @@ module ActiveRecord
|
|
27
28
|
end
|
28
29
|
|
29
30
|
if through_record
|
30
|
-
through_record.
|
31
|
-
|
31
|
+
if through_record.new_record?
|
32
|
+
through_record.assign_attributes(attributes)
|
33
|
+
else
|
34
|
+
through_record.update(attributes)
|
35
|
+
end
|
36
|
+
elsif owner.new_record? || !save
|
32
37
|
through_proxy.build(attributes)
|
33
38
|
else
|
34
39
|
through_proxy.create(attributes)
|
@@ -1,19 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record/associations/join_dependency/join_part"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module Associations
|
5
7
|
class JoinDependency # :nodoc:
|
6
8
|
class JoinAssociation < JoinPart # :nodoc:
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
attr_accessor :tables
|
9
|
+
attr_reader :reflection, :tables
|
10
|
+
attr_accessor :table
|
11
11
|
|
12
12
|
def initialize(reflection, children)
|
13
13
|
super(reflection.klass, children)
|
14
14
|
|
15
|
-
@reflection
|
16
|
-
@tables
|
15
|
+
@reflection = reflection
|
16
|
+
@tables = nil
|
17
17
|
end
|
18
18
|
|
19
19
|
def match?(other)
|
@@ -21,83 +21,38 @@ module ActiveRecord
|
|
21
21
|
super && reflection == other.reflection
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
def join_constraints(foreign_table, foreign_klass, join_type, tables, chain)
|
27
|
-
joins = []
|
28
|
-
binds = []
|
29
|
-
tables = tables.reverse
|
24
|
+
def join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
25
|
+
joins = []
|
30
26
|
|
31
27
|
# The chain starts with the target table, but we want to end with it here (makes
|
32
28
|
# more sense in this context), so we reverse
|
33
|
-
chain.reverse_each do |reflection|
|
34
|
-
table = tables
|
29
|
+
reflection.chain.reverse_each.with_index(1) do |reflection, i|
|
30
|
+
table = tables[-i]
|
35
31
|
klass = reflection.klass
|
36
32
|
|
37
|
-
|
38
|
-
key = join_keys.key
|
39
|
-
foreign_key = join_keys.foreign_key
|
40
|
-
|
41
|
-
constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
|
33
|
+
constraint = reflection.build_join_constraint(table, foreign_table)
|
42
34
|
|
43
|
-
|
44
|
-
|
45
|
-
if rel && !rel.arel.constraints.empty?
|
46
|
-
binds += rel.bound_attributes
|
47
|
-
constraint = constraint.and rel.arel.constraints
|
48
|
-
end
|
35
|
+
joins << table.create_join(table, table.create_on(constraint), join_type)
|
49
36
|
|
50
|
-
|
51
|
-
|
52
|
-
column = klass.columns_hash[reflection.type.to_s]
|
37
|
+
join_scope = reflection.join_scope(table, foreign_klass)
|
38
|
+
arel = join_scope.arel(alias_tracker.aliases)
|
53
39
|
|
54
|
-
|
55
|
-
|
40
|
+
if arel.constraints.any?
|
41
|
+
joins.concat arel.join_sources
|
42
|
+
right = joins.last.right
|
43
|
+
right.expr = right.expr.and(arel.constraints)
|
56
44
|
end
|
57
45
|
|
58
|
-
joins << table.create_join(table, table.create_on(constraint), join_type)
|
59
|
-
|
60
46
|
# The current table in this iteration becomes the foreign table in the next
|
61
47
|
foreign_table, foreign_klass = table, klass
|
62
48
|
end
|
63
49
|
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
# Builds equality condition.
|
68
|
-
#
|
69
|
-
# Example:
|
70
|
-
#
|
71
|
-
# class Physician < ActiveRecord::Base
|
72
|
-
# has_many :appointments
|
73
|
-
# end
|
74
|
-
#
|
75
|
-
# If I execute `Physician.joins(:appointments).to_a` then
|
76
|
-
# klass # => Physician
|
77
|
-
# table # => #<Arel::Table @name="appointments" ...>
|
78
|
-
# key # => physician_id
|
79
|
-
# foreign_table # => #<Arel::Table @name="physicians" ...>
|
80
|
-
# foreign_key # => id
|
81
|
-
#
|
82
|
-
def build_constraint(klass, table, key, foreign_table, foreign_key)
|
83
|
-
constraint = table[key].eq(foreign_table[foreign_key])
|
84
|
-
|
85
|
-
if klass.finder_needs_type_condition?
|
86
|
-
constraint = table.create_and([
|
87
|
-
constraint,
|
88
|
-
klass.send(:type_condition, table)
|
89
|
-
])
|
90
|
-
end
|
91
|
-
|
92
|
-
constraint
|
93
|
-
end
|
94
|
-
|
95
|
-
def table
|
96
|
-
tables.first
|
50
|
+
joins
|
97
51
|
end
|
98
52
|
|
99
|
-
def
|
100
|
-
|
53
|
+
def tables=(tables)
|
54
|
+
@tables = tables
|
55
|
+
@table = tables.first
|
101
56
|
end
|
102
57
|
end
|
103
58
|
end
|