activerecord 4.2.11.3 → 5.0.7.2
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 +1638 -1132
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +7 -2
- data/lib/active_record/aggregations.rb +34 -21
- data/lib/active_record/association_relation.rb +7 -4
- data/lib/active_record/associations.rb +347 -218
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +22 -10
- data/lib/active_record/associations/association_scope.rb +75 -104
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +13 -11
- data/lib/active_record/associations/collection_association.rb +85 -69
- data/lib/active_record/associations/collection_proxy.rb +104 -46
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +21 -78
- data/lib/active_record/associations/has_many_through_association.rb +6 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +38 -22
- data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +52 -71
- data/lib/active_record/associations/preloader/collection_association.rb +0 -7
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +36 -17
- data/lib/active_record/associations/singular_association.rb +13 -1
- data/lib/active_record/associations/through_association.rb +12 -4
- data/lib/active_record/attribute.rb +69 -19
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +69 -44
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +16 -3
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +32 -3
- data/lib/active_record/attribute_set/builder.rb +42 -16
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +54 -17
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +92 -108
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +116 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +77 -41
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +17 -14
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +48 -24
- data/lib/active_record/migration.rb +362 -111
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +270 -73
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +152 -90
- data/lib/active_record/query_cache.rb +18 -23
- data/lib/active_record/querying.rb +12 -11
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +52 -41
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +302 -115
- data/lib/active_record/relation.rb +187 -120
- data/lib/active_record/relation/batches.rb +141 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +92 -117
- data/lib/active_record/relation/delegation.rb +8 -20
- data/lib/active_record/relation/finder_methods.rb +173 -89
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +11 -4
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +105 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +54 -37
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +34 -16
- data/lib/active_record/scoping/default.rb +28 -10
- data/lib/active_record/scoping/named.rb +59 -26
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +3 -5
- data/lib/active_record/statement_cache.rb +17 -15
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +69 -0
- data/lib/active_record/tasks/database_tasks.rb +66 -49
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +63 -0
- data/lib/active_record/transactions.rb +139 -57
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +33 -33
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +58 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -15,9 +15,16 @@ module ActiveRecord
|
|
15
15
|
|
16
16
|
when :restrict_with_error
|
17
17
|
unless empty?
|
18
|
-
record =
|
19
|
-
owner.errors.
|
20
|
-
|
18
|
+
record = owner.class.human_attribute_name(reflection.name).downcase
|
19
|
+
message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.many', record: record, raise: true) rescue nil
|
20
|
+
if message
|
21
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
|
22
|
+
The error key `:'restrict_dependent_destroy.many'` has been deprecated and will be removed in Rails 5.1.
|
23
|
+
Please use `:'restrict_dependent_destroy.has_many'` instead.
|
24
|
+
MESSAGE
|
25
|
+
end
|
26
|
+
owner.errors.add(:base, message || :'restrict_dependent_destroy.has_many', record: record)
|
27
|
+
throw(:abort)
|
21
28
|
end
|
22
29
|
|
23
30
|
else
|
@@ -33,17 +40,11 @@ module ActiveRecord
|
|
33
40
|
|
34
41
|
def insert_record(record, validate = true, raise = false)
|
35
42
|
set_owner_attributes(record)
|
36
|
-
|
37
|
-
|
38
|
-
if raise
|
39
|
-
record.save!(:validate => validate)
|
40
|
-
else
|
41
|
-
record.save(:validate => validate)
|
42
|
-
end
|
43
|
+
super
|
43
44
|
end
|
44
45
|
|
45
46
|
def empty?
|
46
|
-
if has_cached_counter?
|
47
|
+
if reflection.has_cached_counter?
|
47
48
|
size.zero?
|
48
49
|
else
|
49
50
|
super
|
@@ -66,8 +67,8 @@ module ActiveRecord
|
|
66
67
|
# If the collection is empty the target is set to an empty array and
|
67
68
|
# the loaded flag is set to true as well.
|
68
69
|
def count_records
|
69
|
-
count = if has_cached_counter?
|
70
|
-
owner._read_attribute
|
70
|
+
count = if reflection.has_cached_counter?
|
71
|
+
owner._read_attribute reflection.counter_cache_column
|
71
72
|
else
|
72
73
|
scope.count
|
73
74
|
end
|
@@ -80,78 +81,20 @@ module ActiveRecord
|
|
80
81
|
[association_scope.limit_value, count].compact.min
|
81
82
|
end
|
82
83
|
|
83
|
-
|
84
|
-
# Returns whether a counter cache should be used for this association.
|
85
|
-
#
|
86
|
-
# The counter_cache option must be given on either the owner or inverse
|
87
|
-
# association, and the column must be present on the owner.
|
88
|
-
def has_cached_counter?(reflection = reflection())
|
89
|
-
if reflection.options[:counter_cache] || (inverse = inverse_which_updates_counter_cache(reflection)) && inverse.options[:counter_cache]
|
90
|
-
owner.attribute_present?(cached_counter_attribute_name(reflection))
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def cached_counter_attribute_name(reflection = reflection())
|
95
|
-
if reflection.options[:counter_cache]
|
96
|
-
reflection.options[:counter_cache].to_s
|
97
|
-
else
|
98
|
-
"#{reflection.name}_count"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
84
|
def update_counter(difference, reflection = reflection())
|
103
|
-
|
104
|
-
|
105
|
-
end
|
106
|
-
|
107
|
-
def update_counter_in_database(difference, reflection = reflection())
|
108
|
-
if has_cached_counter?(reflection)
|
109
|
-
counter = cached_counter_attribute_name(reflection)
|
110
|
-
owner.class.update_counters(owner.id, counter => difference)
|
85
|
+
if reflection.has_cached_counter?
|
86
|
+
owner.increment!(reflection.counter_cache_column, difference)
|
111
87
|
end
|
112
88
|
end
|
113
89
|
|
114
90
|
def update_counter_in_memory(difference, reflection = reflection())
|
115
|
-
if counter_must_be_updated_by_has_many?
|
116
|
-
counter =
|
117
|
-
owner
|
118
|
-
owner.send(:
|
91
|
+
if reflection.counter_must_be_updated_by_has_many?
|
92
|
+
counter = reflection.counter_cache_column
|
93
|
+
owner.increment(counter, difference)
|
94
|
+
owner.send(:clear_attribute_change, counter) # eww
|
119
95
|
end
|
120
96
|
end
|
121
97
|
|
122
|
-
# This shit is nasty. We need to avoid the following situation:
|
123
|
-
#
|
124
|
-
# * An associated record is deleted via record.destroy
|
125
|
-
# * Hence the callbacks run, and they find a belongs_to on the record with a
|
126
|
-
# :counter_cache options which points back at our owner. So they update the
|
127
|
-
# counter cache.
|
128
|
-
# * In which case, we must make sure to *not* update the counter cache, or else
|
129
|
-
# it will be decremented twice.
|
130
|
-
#
|
131
|
-
# Hence this method.
|
132
|
-
def inverse_which_updates_counter_cache(reflection = reflection())
|
133
|
-
counter_name = cached_counter_attribute_name(reflection)
|
134
|
-
inverse_which_updates_counter_named(counter_name, reflection)
|
135
|
-
end
|
136
|
-
alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
|
137
|
-
|
138
|
-
def inverse_which_updates_counter_named(counter_name, reflection)
|
139
|
-
reflection.klass._reflections.values.find { |inverse_reflection|
|
140
|
-
inverse_reflection.belongs_to? &&
|
141
|
-
inverse_reflection.counter_cache_column == counter_name
|
142
|
-
}
|
143
|
-
end
|
144
|
-
alias inverse_updates_counter_named? inverse_which_updates_counter_named
|
145
|
-
|
146
|
-
def inverse_updates_counter_in_memory?(reflection)
|
147
|
-
inverse = inverse_which_updates_counter_cache(reflection)
|
148
|
-
inverse && inverse == reflection.inverse_of
|
149
|
-
end
|
150
|
-
|
151
|
-
def counter_must_be_updated_by_has_many?(reflection)
|
152
|
-
!inverse_updates_counter_in_memory?(reflection) && has_cached_counter?(reflection)
|
153
|
-
end
|
154
|
-
|
155
98
|
def delete_count(method, scope)
|
156
99
|
if method == :delete_all
|
157
100
|
scope.delete_all
|
@@ -169,7 +112,7 @@ module ActiveRecord
|
|
169
112
|
def delete_records(records, method)
|
170
113
|
if method == :destroy
|
171
114
|
records.each(&:destroy!)
|
172
|
-
update_counter(-records.length) unless inverse_updates_counter_cache?
|
115
|
+
update_counter(-records.length) unless reflection.inverse_updates_counter_cache?
|
173
116
|
else
|
174
117
|
scope = self.scope.where(reflection.klass.primary_key => records)
|
175
118
|
update_counter(-delete_count(method, scope))
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/string/filters'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
# = Active Record Has Many Through Association
|
5
3
|
module Associations
|
@@ -13,21 +11,6 @@ module ActiveRecord
|
|
13
11
|
@through_association = nil
|
14
12
|
end
|
15
13
|
|
16
|
-
# Returns the size of the collection by executing a SELECT COUNT(*) query
|
17
|
-
# if the collection hasn't been loaded, and by calling collection.size if
|
18
|
-
# it has. If the collection will likely have a size greater than zero,
|
19
|
-
# and if fetching the collection will be needed afterwards, one less
|
20
|
-
# SELECT query will be generated by using #length instead.
|
21
|
-
def size
|
22
|
-
if has_cached_counter?
|
23
|
-
owner._read_attribute cached_counter_attribute_name(reflection)
|
24
|
-
elsif loaded?
|
25
|
-
target.size
|
26
|
-
else
|
27
|
-
super
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
14
|
def concat(*records)
|
32
15
|
unless owner.new_record?
|
33
16
|
records.flatten.each do |record|
|
@@ -55,25 +38,12 @@ module ActiveRecord
|
|
55
38
|
def insert_record(record, validate = true, raise = false)
|
56
39
|
ensure_not_nested
|
57
40
|
|
58
|
-
if record.new_record?
|
59
|
-
|
60
|
-
record.save!(:validate => validate)
|
61
|
-
else
|
62
|
-
return unless record.save(:validate => validate)
|
63
|
-
end
|
41
|
+
if record.new_record? || record.changed?
|
42
|
+
return unless super
|
64
43
|
end
|
65
44
|
|
66
45
|
save_through_record(record)
|
67
|
-
if has_cached_counter? && !through_reflection_updates_counter_cache?
|
68
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
69
|
-
Automatic updating of counter caches on through associations has been
|
70
|
-
deprecated, and will be removed in Rails 5. Instead, please set the
|
71
|
-
appropriate `counter_cache` options on the `has_many` and `belongs_to`
|
72
|
-
for your associations to #{through_reflection.name}.
|
73
|
-
MSG
|
74
46
|
|
75
|
-
update_counter_in_database(1)
|
76
|
-
end
|
77
47
|
record
|
78
48
|
end
|
79
49
|
|
@@ -143,7 +113,7 @@ module ActiveRecord
|
|
143
113
|
def update_through_counter?(method)
|
144
114
|
case method
|
145
115
|
when :destroy
|
146
|
-
!inverse_updates_counter_cache?
|
116
|
+
!through_reflection.inverse_updates_counter_cache?
|
147
117
|
when :nullify
|
148
118
|
false
|
149
119
|
else
|
@@ -166,17 +136,15 @@ module ActiveRecord
|
|
166
136
|
if scope.klass.primary_key
|
167
137
|
count = scope.destroy_all.length
|
168
138
|
else
|
169
|
-
scope.each
|
170
|
-
record._run_destroy_callbacks
|
171
|
-
end
|
139
|
+
scope.each(&:_run_destroy_callbacks)
|
172
140
|
|
173
141
|
arel = scope.arel
|
174
142
|
|
175
|
-
stmt = Arel::DeleteManager.new
|
143
|
+
stmt = Arel::DeleteManager.new
|
176
144
|
stmt.from scope.klass.arel_table
|
177
145
|
stmt.wheres = arel.constraints
|
178
146
|
|
179
|
-
count = scope.klass.connection.delete(stmt, 'SQL', scope.
|
147
|
+
count = scope.klass.connection.delete(stmt, 'SQL', scope.bound_attributes)
|
180
148
|
end
|
181
149
|
when :nullify
|
182
150
|
count = scope.update_all(source_reflection.foreign_key => nil)
|
@@ -233,15 +201,6 @@ module ActiveRecord
|
|
233
201
|
def invertible_for?(record)
|
234
202
|
false
|
235
203
|
end
|
236
|
-
|
237
|
-
def has_cached_counter?(reflection = reflection())
|
238
|
-
owner.attribute_present?(cached_counter_attribute_name(reflection))
|
239
|
-
end
|
240
|
-
|
241
|
-
def through_reflection_updates_counter_cache?
|
242
|
-
counter_name = cached_counter_attribute_name
|
243
|
-
inverse_updates_counter_named?(counter_name, through_reflection)
|
244
|
-
end
|
245
204
|
end
|
246
205
|
end
|
247
206
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
# = Active Record
|
2
|
+
# = Active Record Has One Association
|
3
3
|
module Associations
|
4
4
|
class HasOneAssociation < SingularAssociation #:nodoc:
|
5
5
|
include ForeignAssociation
|
@@ -11,9 +11,16 @@ module ActiveRecord
|
|
11
11
|
|
12
12
|
when :restrict_with_error
|
13
13
|
if load_target
|
14
|
-
record =
|
15
|
-
owner.errors.
|
16
|
-
|
14
|
+
record = owner.class.human_attribute_name(reflection.name).downcase
|
15
|
+
message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.one', record: record, raise: true) rescue nil
|
16
|
+
if message
|
17
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
|
18
|
+
The error key `:'restrict_dependent_destroy.one'` has been deprecated and will be removed in Rails 5.1.
|
19
|
+
Please use `:'restrict_dependent_destroy.has_one'` instead.
|
20
|
+
MESSAGE
|
21
|
+
end
|
22
|
+
owner.errors.add(:base, message || :'restrict_dependent_destroy.has_one', record: record)
|
23
|
+
throw(:abort)
|
17
24
|
end
|
18
25
|
|
19
26
|
else
|
@@ -58,7 +65,7 @@ module ActiveRecord
|
|
58
65
|
when :destroy
|
59
66
|
target.destroy
|
60
67
|
when :nullify
|
61
|
-
target.update_columns(reflection.foreign_key => nil)
|
68
|
+
target.update_columns(reflection.foreign_key => nil) if target.persisted?
|
62
69
|
end
|
63
70
|
end
|
64
71
|
end
|
@@ -20,7 +20,7 @@ module ActiveRecord
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def columns
|
23
|
-
@tables.flat_map
|
23
|
+
@tables.flat_map(&:column_aliases)
|
24
24
|
end
|
25
25
|
|
26
26
|
# An array of [column_name, alias] pairs for the table
|
@@ -32,7 +32,7 @@ module ActiveRecord
|
|
32
32
|
@alias_cache[node][column]
|
33
33
|
end
|
34
34
|
|
35
|
-
class Table < Struct.new(:node, :columns)
|
35
|
+
class Table < Struct.new(:node, :columns) # :nodoc:
|
36
36
|
def table
|
37
37
|
Arel::Nodes::TableAlias.new node.table, node.aliased_table_name
|
38
38
|
end
|
@@ -93,8 +93,7 @@ module ActiveRecord
|
|
93
93
|
# joins # => []
|
94
94
|
#
|
95
95
|
def initialize(base, associations, joins)
|
96
|
-
@alias_tracker = AliasTracker.
|
97
|
-
@alias_tracker.aliased_table_for(base.table_name, base.table_name) # Updates the count for base.table_name to 1
|
96
|
+
@alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins, base.type_caster)
|
98
97
|
tree = self.class.make_tree associations
|
99
98
|
@join_root = JoinBase.new base, build(tree, base)
|
100
99
|
@join_root.children.each { |child| construct_tables! @join_root, child }
|
@@ -104,9 +103,14 @@ module ActiveRecord
|
|
104
103
|
join_root.drop(1).map!(&:reflection)
|
105
104
|
end
|
106
105
|
|
107
|
-
def join_constraints(outer_joins)
|
106
|
+
def join_constraints(outer_joins, join_type)
|
108
107
|
joins = join_root.children.flat_map { |child|
|
109
|
-
|
108
|
+
|
109
|
+
if join_type == Arel::Nodes::OuterJoin
|
110
|
+
make_left_outer_joins join_root, child
|
111
|
+
else
|
112
|
+
make_inner_joins join_root, child
|
113
|
+
end
|
110
114
|
}
|
111
115
|
|
112
116
|
joins.concat outer_joins.flat_map { |oj|
|
@@ -132,9 +136,9 @@ module ActiveRecord
|
|
132
136
|
def instantiate(result_set, aliases)
|
133
137
|
primary_key = aliases.column_alias(join_root, join_root.primary_key)
|
134
138
|
|
135
|
-
seen = Hash.new { |
|
136
|
-
|
137
|
-
|
139
|
+
seen = Hash.new { |i, object_id|
|
140
|
+
i[object_id] = Hash.new { |j, child_class|
|
141
|
+
j[child_class] = {}
|
138
142
|
}
|
139
143
|
}
|
140
144
|
|
@@ -177,6 +181,14 @@ module ActiveRecord
|
|
177
181
|
[info] + child.children.flat_map { |c| make_outer_joins(child, c) }
|
178
182
|
end
|
179
183
|
|
184
|
+
def make_left_outer_joins(parent, child)
|
185
|
+
tables = child.tables
|
186
|
+
join_type = Arel::Nodes::OuterJoin
|
187
|
+
info = make_constraints parent, child, tables, join_type
|
188
|
+
|
189
|
+
[info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
|
190
|
+
end
|
191
|
+
|
180
192
|
def make_inner_joins(parent, child)
|
181
193
|
tables = child.tables
|
182
194
|
join_type = Arel::Nodes::InnerJoin
|
@@ -216,7 +228,7 @@ module ActiveRecord
|
|
216
228
|
|
217
229
|
def find_reflection(klass, name)
|
218
230
|
klass._reflect_on_association(name) or
|
219
|
-
raise ConfigurationError, "
|
231
|
+
raise ConfigurationError, "Can't join '#{ klass.name }' to association named '#{ name }'; perhaps you misspelled it?"
|
220
232
|
end
|
221
233
|
|
222
234
|
def build(associations, base_klass)
|
@@ -235,18 +247,15 @@ module ActiveRecord
|
|
235
247
|
|
236
248
|
def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
|
237
249
|
return if ar_parent.nil?
|
238
|
-
primary_id = ar_parent.id
|
239
250
|
|
240
251
|
parent.children.each do |node|
|
241
252
|
if node.reflection.collection?
|
242
253
|
other = ar_parent.association(node.reflection.name)
|
243
254
|
other.loaded!
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
next
|
249
|
-
end
|
255
|
+
elsif ar_parent.association_cached?(node.reflection.name)
|
256
|
+
model = ar_parent.association(node.reflection.name).target
|
257
|
+
construct(model, node, row, rs, seen, model_cache, aliases)
|
258
|
+
next
|
250
259
|
end
|
251
260
|
|
252
261
|
key = aliases.column_alias(node, node.primary_key)
|
@@ -257,30 +266,37 @@ module ActiveRecord
|
|
257
266
|
next
|
258
267
|
end
|
259
268
|
|
260
|
-
model = seen[
|
269
|
+
model = seen[ar_parent.object_id][node.base_klass][id]
|
261
270
|
|
262
271
|
if model
|
263
272
|
construct(model, node, row, rs, seen, model_cache, aliases)
|
264
273
|
else
|
265
274
|
model = construct_model(ar_parent, node, row, model_cache, id, aliases)
|
266
|
-
|
275
|
+
|
276
|
+
if node.reflection.scope_for(node.base_klass).readonly_value
|
277
|
+
model.readonly!
|
278
|
+
end
|
279
|
+
|
280
|
+
seen[ar_parent.object_id][node.base_klass][id] = model
|
267
281
|
construct(model, node, row, rs, seen, model_cache, aliases)
|
268
282
|
end
|
269
283
|
end
|
270
284
|
end
|
271
285
|
|
272
286
|
def construct_model(record, node, row, model_cache, id, aliases)
|
273
|
-
model = model_cache[node][id] ||= node.instantiate(row,
|
274
|
-
aliases.column_aliases(node))
|
275
287
|
other = record.association(node.reflection.name)
|
276
288
|
|
289
|
+
model = model_cache[node][id] ||=
|
290
|
+
node.instantiate(row, aliases.column_aliases(node)) do |m|
|
291
|
+
other.set_inverse_instance(m)
|
292
|
+
end
|
293
|
+
|
277
294
|
if node.reflection.collection?
|
278
295
|
other.target.push(model)
|
279
296
|
else
|
280
297
|
other.target = model
|
281
298
|
end
|
282
299
|
|
283
|
-
other.set_inverse_instance(model)
|
284
300
|
model
|
285
301
|
end
|
286
302
|
end
|
@@ -25,7 +25,7 @@ module ActiveRecord
|
|
25
25
|
|
26
26
|
def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
|
27
27
|
joins = []
|
28
|
-
|
28
|
+
binds = []
|
29
29
|
tables = tables.reverse
|
30
30
|
|
31
31
|
scope_chain_index = 0
|
@@ -43,29 +43,31 @@ module ActiveRecord
|
|
43
43
|
|
44
44
|
constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
|
45
45
|
|
46
|
+
predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
|
46
47
|
scope_chain_items = scope_chain[scope_chain_index].map do |item|
|
47
48
|
if item.is_a?(Relation)
|
48
49
|
item
|
49
50
|
else
|
50
|
-
ActiveRecord::Relation.create(klass, table
|
51
|
+
ActiveRecord::Relation.create(klass, table, predicate_builder)
|
52
|
+
.instance_exec(node, &item)
|
51
53
|
end
|
52
54
|
end
|
53
55
|
scope_chain_index += 1
|
54
56
|
|
57
|
+
relation = ActiveRecord::Relation.create(klass, table, predicate_builder)
|
58
|
+
current_scope = klass.current_scope
|
59
|
+
|
55
60
|
klass_scope =
|
56
|
-
if
|
57
|
-
|
61
|
+
if current_scope && current_scope.empty_scope?
|
62
|
+
relation
|
58
63
|
else
|
59
|
-
klass.send(:build_default_scope,
|
64
|
+
klass.send(:build_default_scope, relation)
|
60
65
|
end
|
61
|
-
scope_chain_items.concat [klass_scope].compact
|
62
66
|
|
63
|
-
rel = scope_chain_items.inject(scope_chain_items.shift
|
64
|
-
left.merge right
|
65
|
-
end
|
67
|
+
rel = scope_chain_items.inject(klass_scope || scope_chain_items.shift, &:merge!)
|
66
68
|
|
67
69
|
if rel && !rel.arel.constraints.empty?
|
68
|
-
|
70
|
+
binds += rel.bound_attributes
|
69
71
|
constraint = constraint.and rel.arel.constraints
|
70
72
|
end
|
71
73
|
|
@@ -73,9 +75,8 @@ module ActiveRecord
|
|
73
75
|
value = foreign_klass.base_class.name
|
74
76
|
column = klass.columns_hash[reflection.type.to_s]
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
-
constraint = constraint.and table[reflection.type].eq substitute
|
78
|
+
binds << Relation::QueryAttribute.new(column.name, value, klass.type_for_attribute(column.name))
|
79
|
+
constraint = constraint.and klass.arel_attribute(reflection.type, table).eq(Arel::Nodes::BindParam.new)
|
79
80
|
end
|
80
81
|
|
81
82
|
joins << table.create_join(table, table.create_on(constraint), join_type)
|
@@ -84,7 +85,7 @@ module ActiveRecord
|
|
84
85
|
foreign_table, foreign_klass = table, klass
|
85
86
|
end
|
86
87
|
|
87
|
-
JoinInformation.new joins,
|
88
|
+
JoinInformation.new joins, binds
|
88
89
|
end
|
89
90
|
|
90
91
|
# Builds equality condition.
|