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
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -26,7 +26,7 @@ The Product class is automatically mapped to the table named "products",
|
|
26
26
|
which might look like this:
|
27
27
|
|
28
28
|
CREATE TABLE products (
|
29
|
-
id
|
29
|
+
id bigint NOT NULL auto_increment,
|
30
30
|
name varchar(255),
|
31
31
|
PRIMARY KEY (id)
|
32
32
|
);
|
@@ -162,7 +162,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
|
|
162
162
|
== Philosophy
|
163
163
|
|
164
164
|
Active Record is an implementation of the object-relational mapping (ORM)
|
165
|
-
pattern[
|
165
|
+
pattern[https://www.martinfowler.com/eaaCatalog/activeRecord.html] by the same
|
166
166
|
name described by Martin Fowler:
|
167
167
|
|
168
168
|
"An object that wraps a row in a database table or view,
|
@@ -192,14 +192,14 @@ The latest version of Active Record can be installed with RubyGems:
|
|
192
192
|
|
193
193
|
Source code can be downloaded as part of the Rails project on GitHub:
|
194
194
|
|
195
|
-
* https://github.com/rails/rails/tree/
|
195
|
+
* https://github.com/rails/rails/tree/5-2-stable/activerecord
|
196
196
|
|
197
197
|
|
198
198
|
== License
|
199
199
|
|
200
200
|
Active Record is released under the MIT license:
|
201
201
|
|
202
|
-
*
|
202
|
+
* https://opensource.org/licenses/MIT
|
203
203
|
|
204
204
|
|
205
205
|
== Support
|
@@ -208,7 +208,7 @@ API documentation is at:
|
|
208
208
|
|
209
209
|
* http://api.rubyonrails.org
|
210
210
|
|
211
|
-
Bug reports
|
211
|
+
Bug reports for the Ruby on Rails project can be filed here:
|
212
212
|
|
213
213
|
* https://github.com/rails/rails/issues
|
214
214
|
|
data/examples/performance.rb
CHANGED
data/examples/simple.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
# See ActiveRecord::Aggregations::ClassMethods for documentation
|
3
5
|
module Aggregations
|
@@ -33,7 +35,7 @@ module ActiveRecord
|
|
33
35
|
# the database).
|
34
36
|
#
|
35
37
|
# class Customer < ActiveRecord::Base
|
36
|
-
# composed_of :balance, class_name: "Money", mapping: %w(amount
|
38
|
+
# composed_of :balance, class_name: "Money", mapping: %w(balance amount)
|
37
39
|
# composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
|
38
40
|
# end
|
39
41
|
#
|
@@ -175,9 +177,9 @@ module ActiveRecord
|
|
175
177
|
#
|
176
178
|
# Once a #composed_of relationship is specified for a model, records can be loaded from the database
|
177
179
|
# by specifying an instance of the value object in the conditions hash. The following example
|
178
|
-
# finds all customers with +
|
180
|
+
# finds all customers with +address_street+ equal to "May Street" and +address_city+ equal to "Chicago":
|
179
181
|
#
|
180
|
-
# Customer.where(
|
182
|
+
# Customer.where(address: Address.new("May Street", "Chicago"))
|
181
183
|
#
|
182
184
|
module ClassMethods
|
183
185
|
# Adds reader and writer methods for manipulating a value object:
|
@@ -210,8 +212,7 @@ module ActiveRecord
|
|
210
212
|
#
|
211
213
|
# Option examples:
|
212
214
|
# composed_of :temperature, mapping: %w(reading celsius)
|
213
|
-
# composed_of :balance, class_name: "Money", mapping: %w(balance amount)
|
214
|
-
# converter: Proc.new { |balance| balance.to_money }
|
215
|
+
# composed_of :balance, class_name: "Money", mapping: %w(balance amount)
|
215
216
|
# composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
|
216
217
|
# composed_of :gps_location
|
217
218
|
# composed_of :gps_location, allow_nil: true
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
class AssociationRelation < Relation
|
3
|
-
def initialize(klass,
|
4
|
-
super(klass
|
5
|
+
def initialize(klass, association)
|
6
|
+
super(klass)
|
5
7
|
@association = association
|
6
8
|
end
|
7
9
|
|
@@ -1,51 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/string/conversions"
|
2
4
|
|
3
5
|
module ActiveRecord
|
4
6
|
module Associations
|
5
7
|
# Keeps track of table aliases for ActiveRecord::Associations::JoinDependency
|
6
8
|
class AliasTracker # :nodoc:
|
7
|
-
|
8
|
-
|
9
|
-
def self.create(connection, initial_table)
|
10
|
-
aliases = Hash.new(0)
|
11
|
-
aliases[initial_table] = 1
|
12
|
-
new(connection, aliases)
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.create_with_joins(connection, initial_table, joins)
|
9
|
+
def self.create(connection, initial_table, joins)
|
16
10
|
if joins.empty?
|
17
|
-
|
11
|
+
aliases = Hash.new(0)
|
18
12
|
else
|
19
13
|
aliases = Hash.new { |h, k|
|
20
14
|
h[k] = initial_count_for(connection, k, joins)
|
21
15
|
}
|
22
|
-
aliases[initial_table] = 1
|
23
|
-
new(connection, aliases)
|
24
16
|
end
|
17
|
+
aliases[initial_table] = 1
|
18
|
+
new(connection, aliases)
|
25
19
|
end
|
26
20
|
|
27
21
|
def self.initial_count_for(connection, name, table_joins)
|
28
|
-
|
29
|
-
quoted_name = connection.quote_table_name(name).downcase
|
22
|
+
quoted_name = nil
|
30
23
|
|
31
24
|
counts = table_joins.map do |join|
|
32
25
|
if join.is_a?(Arel::Nodes::StringJoin)
|
26
|
+
# quoted_name should be case ignored as some database adapters (Oracle) return quoted name in uppercase
|
27
|
+
quoted_name ||= connection.quote_table_name(name)
|
28
|
+
|
33
29
|
# Table names + table aliases
|
34
|
-
join.left.
|
35
|
-
/
|
30
|
+
join.left.scan(
|
31
|
+
/JOIN(?:\s+\w+)?\s+(?:\S+\s+)?(?:#{quoted_name}|#{name})\sON/i
|
36
32
|
).size
|
37
|
-
elsif join.
|
38
|
-
join.left.
|
33
|
+
elsif join.is_a?(Arel::Nodes::Join)
|
34
|
+
join.left.name == name ? 1 : 0
|
35
|
+
elsif join.is_a?(Hash)
|
36
|
+
join[name]
|
39
37
|
else
|
40
|
-
|
41
|
-
#
|
42
|
-
# activerecord/test/cases/associations/cascaded_eager_loading_test.rb:37
|
43
|
-
# with :posts
|
44
|
-
#
|
45
|
-
# activerecord/test/cases/associations/eager_test.rb:1133
|
46
|
-
# with :comments
|
47
|
-
#
|
48
|
-
0
|
38
|
+
raise ArgumentError, "joins list should be initialized by list of Arel::Nodes::Join"
|
49
39
|
end
|
50
40
|
end
|
51
41
|
|
@@ -79,6 +69,8 @@ module ActiveRecord
|
|
79
69
|
end
|
80
70
|
end
|
81
71
|
|
72
|
+
attr_reader :aliases
|
73
|
+
|
82
74
|
private
|
83
75
|
|
84
76
|
def truncate(name)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/array/wrap"
|
2
4
|
|
3
5
|
module ActiveRecord
|
@@ -17,7 +19,6 @@ module ActiveRecord
|
|
17
19
|
# HasManyThroughAssociation + ThroughAssociation
|
18
20
|
class Association #:nodoc:
|
19
21
|
attr_reader :owner, :target, :reflection
|
20
|
-
attr_accessor :inversed
|
21
22
|
|
22
23
|
delegate :options, to: :reflection
|
23
24
|
|
@@ -30,14 +31,6 @@ module ActiveRecord
|
|
30
31
|
reset_scope
|
31
32
|
end
|
32
33
|
|
33
|
-
# Returns the name of the table of the associated class:
|
34
|
-
#
|
35
|
-
# post.comments.aliased_table_name # => "comments"
|
36
|
-
#
|
37
|
-
def aliased_table_name
|
38
|
-
klass.table_name
|
39
|
-
end
|
40
|
-
|
41
34
|
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
|
42
35
|
def reset
|
43
36
|
@loaded = false
|
@@ -73,7 +66,7 @@ module ActiveRecord
|
|
73
66
|
#
|
74
67
|
# Note that if the target has not been loaded, it is not considered stale.
|
75
68
|
def stale_target?
|
76
|
-
|
69
|
+
!@inversed && loaded? && @stale_state != stale_state
|
77
70
|
end
|
78
71
|
|
79
72
|
# Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
|
@@ -94,7 +87,7 @@ module ActiveRecord
|
|
94
87
|
# actually gets built.
|
95
88
|
def association_scope
|
96
89
|
if klass
|
97
|
-
@association_scope ||= AssociationScope.scope(self
|
90
|
+
@association_scope ||= AssociationScope.scope(self)
|
98
91
|
end
|
99
92
|
end
|
100
93
|
|
@@ -104,23 +97,24 @@ module ActiveRecord
|
|
104
97
|
|
105
98
|
# Set the inverse association, if possible
|
106
99
|
def set_inverse_instance(record)
|
107
|
-
if
|
108
|
-
inverse
|
109
|
-
inverse.target = owner
|
110
|
-
inverse.inversed = true
|
100
|
+
if inverse = inverse_association_for(record)
|
101
|
+
inverse.inversed_from(owner)
|
111
102
|
end
|
112
103
|
record
|
113
104
|
end
|
114
105
|
|
115
106
|
# Remove the inverse association, if possible
|
116
107
|
def remove_inverse_instance(record)
|
117
|
-
if
|
118
|
-
inverse
|
119
|
-
inverse.target = nil
|
120
|
-
inverse.inversed = false
|
108
|
+
if inverse = inverse_association_for(record)
|
109
|
+
inverse.inversed_from(nil)
|
121
110
|
end
|
122
111
|
end
|
123
112
|
|
113
|
+
def inversed_from(record)
|
114
|
+
self.target = record
|
115
|
+
@inversed = !!record
|
116
|
+
end
|
117
|
+
|
124
118
|
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
|
125
119
|
# polymorphic_type field on the owner.
|
126
120
|
def klass
|
@@ -130,14 +124,14 @@ module ActiveRecord
|
|
130
124
|
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
|
131
125
|
# through association's scope)
|
132
126
|
def target_scope
|
133
|
-
AssociationRelation.create(klass,
|
127
|
+
AssociationRelation.create(klass, self).merge!(klass.all)
|
134
128
|
end
|
135
129
|
|
136
130
|
def extensions
|
137
131
|
extensions = klass.default_extensions | reflection.extensions
|
138
132
|
|
139
|
-
if
|
140
|
-
extensions |= klass.unscoped
|
133
|
+
if reflection.scope
|
134
|
+
extensions |= reflection.scope_for(klass.unscoped, owner).extensions
|
141
135
|
end
|
142
136
|
|
143
137
|
extensions
|
@@ -162,17 +156,9 @@ module ActiveRecord
|
|
162
156
|
reset
|
163
157
|
end
|
164
158
|
|
165
|
-
|
166
|
-
if sql.respond_to?(:to_proc)
|
167
|
-
owner.instance_exec(record, &sql)
|
168
|
-
else
|
169
|
-
sql
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# We can't dump @reflection since it contains the scope proc
|
159
|
+
# We can't dump @reflection and @through_reflection since it contains the scope proc
|
174
160
|
def marshal_dump
|
175
|
-
ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
|
161
|
+
ivars = (instance_variables - [:@reflection, :@through_reflection]).map { |name| [name, instance_variable_get(name)] }
|
176
162
|
[@reflection.name, ivars]
|
177
163
|
end
|
178
164
|
|
@@ -187,8 +173,8 @@ module ActiveRecord
|
|
187
173
|
skip_assign = [reflection.foreign_key, reflection.type].compact
|
188
174
|
assigned_keys = record.changed_attribute_names_to_save
|
189
175
|
assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
|
190
|
-
attributes =
|
191
|
-
record.
|
176
|
+
attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
|
177
|
+
record.send(:_assign_attributes, attributes) if attributes.any?
|
192
178
|
set_inverse_instance(record)
|
193
179
|
end
|
194
180
|
|
@@ -201,6 +187,9 @@ module ActiveRecord
|
|
201
187
|
end
|
202
188
|
|
203
189
|
private
|
190
|
+
def scope_for_create
|
191
|
+
scope.scope_for_create
|
192
|
+
end
|
204
193
|
|
205
194
|
def find_target?
|
206
195
|
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
|
@@ -212,8 +201,8 @@ module ActiveRecord
|
|
212
201
|
if (reflection.has_one? || reflection.collection?) && !options[:through]
|
213
202
|
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
|
214
203
|
|
215
|
-
if reflection.
|
216
|
-
attributes[reflection.type] = owner.class.
|
204
|
+
if reflection.type
|
205
|
+
attributes[reflection.type] = owner.class.polymorphic_name
|
217
206
|
end
|
218
207
|
end
|
219
208
|
|
@@ -251,6 +240,12 @@ module ActiveRecord
|
|
251
240
|
end
|
252
241
|
end
|
253
242
|
|
243
|
+
def inverse_association_for(record)
|
244
|
+
if invertible_for?(record)
|
245
|
+
record.association(inverse_reflection_for(record).name)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
254
249
|
# Can be redefined by subclasses, notably polymorphic belongs_to
|
255
250
|
# The record parameter is necessary to support polymorphic inverses as we must check for
|
256
251
|
# the association in the specific class of the record.
|
@@ -280,11 +275,12 @@ module ActiveRecord
|
|
280
275
|
def build_record(attributes)
|
281
276
|
reflection.build_association(attributes) do |record|
|
282
277
|
initialize_attributes(record, attributes)
|
278
|
+
yield(record) if block_given?
|
283
279
|
end
|
284
280
|
end
|
285
281
|
|
286
282
|
# Returns true if statement cache should be skipped on the association reader.
|
287
|
-
def skip_statement_cache?
|
283
|
+
def skip_statement_cache?(scope)
|
288
284
|
reflection.has_scope? ||
|
289
285
|
scope.eager_loading? ||
|
290
286
|
klass.scope_attributes? ||
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Associations
|
3
5
|
class AssociationScope #:nodoc:
|
4
|
-
def self.scope(association
|
5
|
-
INSTANCE.scope(association
|
6
|
+
def self.scope(association)
|
7
|
+
INSTANCE.scope(association)
|
6
8
|
end
|
7
9
|
|
8
10
|
def self.create(&block)
|
@@ -16,20 +18,15 @@ module ActiveRecord
|
|
16
18
|
|
17
19
|
INSTANCE = create
|
18
20
|
|
19
|
-
def scope(association
|
21
|
+
def scope(association)
|
20
22
|
klass = association.klass
|
21
23
|
reflection = association.reflection
|
22
24
|
scope = klass.unscoped
|
23
25
|
owner = association.owner
|
24
|
-
|
25
|
-
chain_head, chain_tail = get_chain(reflection, association, alias_tracker)
|
26
|
+
chain = get_chain(reflection, association, scope.alias_tracker)
|
26
27
|
|
27
28
|
scope.extending! reflection.extensions
|
28
|
-
add_constraints(scope, owner,
|
29
|
-
end
|
30
|
-
|
31
|
-
def join_type
|
32
|
-
Arel::Nodes::InnerJoin
|
29
|
+
add_constraints(scope, owner, chain)
|
33
30
|
end
|
34
31
|
|
35
32
|
def self.get_bind_values(owner, chain)
|
@@ -38,12 +35,12 @@ module ActiveRecord
|
|
38
35
|
|
39
36
|
binds << last_reflection.join_id_for(owner)
|
40
37
|
if last_reflection.type
|
41
|
-
binds << owner.class.
|
38
|
+
binds << owner.class.polymorphic_name
|
42
39
|
end
|
43
40
|
|
44
41
|
chain.each_cons(2).each do |reflection, next_reflection|
|
45
42
|
if reflection.type
|
46
|
-
binds << next_reflection.klass.
|
43
|
+
binds << next_reflection.klass.polymorphic_name
|
47
44
|
end
|
48
45
|
end
|
49
46
|
binds
|
@@ -57,19 +54,20 @@ module ActiveRecord
|
|
57
54
|
|
58
55
|
private
|
59
56
|
def join(table, constraint)
|
60
|
-
table.create_join(table, table.create_on(constraint)
|
57
|
+
table.create_join(table, table.create_on(constraint))
|
61
58
|
end
|
62
59
|
|
63
|
-
def last_chain_scope(scope,
|
60
|
+
def last_chain_scope(scope, reflection, owner)
|
64
61
|
join_keys = reflection.join_keys
|
65
62
|
key = join_keys.key
|
66
63
|
foreign_key = join_keys.foreign_key
|
67
64
|
|
65
|
+
table = reflection.aliased_table
|
68
66
|
value = transform_value(owner[foreign_key])
|
69
67
|
scope = apply_scope(scope, table, key, value)
|
70
68
|
|
71
69
|
if reflection.type
|
72
|
-
polymorphic_type = transform_value(owner.class.
|
70
|
+
polymorphic_type = transform_value(owner.class.polymorphic_name)
|
73
71
|
scope = apply_scope(scope, table, reflection.type, polymorphic_type)
|
74
72
|
end
|
75
73
|
|
@@ -80,15 +78,17 @@ module ActiveRecord
|
|
80
78
|
value_transformation.call(value)
|
81
79
|
end
|
82
80
|
|
83
|
-
def next_chain_scope(scope,
|
81
|
+
def next_chain_scope(scope, reflection, next_reflection)
|
84
82
|
join_keys = reflection.join_keys
|
85
83
|
key = join_keys.key
|
86
84
|
foreign_key = join_keys.foreign_key
|
87
85
|
|
86
|
+
table = reflection.aliased_table
|
87
|
+
foreign_table = next_reflection.aliased_table
|
88
88
|
constraint = table[key].eq(foreign_table[foreign_key])
|
89
89
|
|
90
90
|
if reflection.type
|
91
|
-
value = transform_value(next_reflection.klass.
|
91
|
+
value = transform_value(next_reflection.klass.polymorphic_name)
|
92
92
|
scope = apply_scope(scope, table, reflection.type, value)
|
93
93
|
end
|
94
94
|
|
@@ -96,12 +96,11 @@ module ActiveRecord
|
|
96
96
|
end
|
97
97
|
|
98
98
|
class ReflectionProxy < SimpleDelegator # :nodoc:
|
99
|
-
|
100
|
-
attr_reader :alias_name
|
99
|
+
attr_reader :aliased_table
|
101
100
|
|
102
|
-
def initialize(reflection,
|
101
|
+
def initialize(reflection, aliased_table)
|
103
102
|
super(reflection)
|
104
|
-
@
|
103
|
+
@aliased_table = aliased_table
|
105
104
|
end
|
106
105
|
|
107
106
|
def all_includes; nil; end
|
@@ -109,43 +108,34 @@ module ActiveRecord
|
|
109
108
|
|
110
109
|
def get_chain(reflection, association, tracker)
|
111
110
|
name = reflection.name
|
112
|
-
|
113
|
-
previous_reflection = runtime_reflection
|
111
|
+
chain = [Reflection::RuntimeReflection.new(reflection, association)]
|
114
112
|
reflection.chain.drop(1).each do |refl|
|
115
|
-
|
113
|
+
aliased_table = tracker.aliased_table_for(
|
116
114
|
refl.table_name,
|
117
115
|
refl.alias_candidate(name),
|
118
116
|
refl.klass.type_caster
|
119
117
|
)
|
120
|
-
|
121
|
-
previous_reflection.next = proxy
|
122
|
-
previous_reflection = proxy
|
118
|
+
chain << ReflectionProxy.new(refl, aliased_table)
|
123
119
|
end
|
124
|
-
|
120
|
+
chain
|
125
121
|
end
|
126
122
|
|
127
|
-
def add_constraints(scope, owner,
|
128
|
-
|
129
|
-
table = owner_reflection.alias_name
|
130
|
-
scope = last_chain_scope(scope, table, owner_reflection, owner)
|
131
|
-
|
132
|
-
reflection = chain_head
|
133
|
-
while reflection
|
134
|
-
table = reflection.alias_name
|
135
|
-
next_reflection = reflection.next
|
123
|
+
def add_constraints(scope, owner, chain)
|
124
|
+
scope = last_chain_scope(scope, chain.last, owner)
|
136
125
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
end
|
126
|
+
chain.each_cons(2) do |reflection, next_reflection|
|
127
|
+
scope = next_chain_scope(scope, reflection, next_reflection)
|
128
|
+
end
|
141
129
|
|
130
|
+
chain_head = chain.first
|
131
|
+
chain.reverse_each do |reflection|
|
142
132
|
# Exclude the scope of the association itself, because that
|
143
133
|
# was already merged in the #scope method.
|
144
134
|
reflection.constraints.each do |scope_chain_item|
|
145
|
-
item = eval_scope(reflection
|
135
|
+
item = eval_scope(reflection, scope_chain_item, owner)
|
146
136
|
|
147
|
-
if scope_chain_item ==
|
148
|
-
scope.merge! item.except(:where, :includes)
|
137
|
+
if scope_chain_item == chain_head.scope
|
138
|
+
scope.merge! item.except(:where, :includes, :unscope, :order)
|
149
139
|
end
|
150
140
|
|
151
141
|
reflection.all_includes do
|
@@ -154,10 +144,8 @@ module ActiveRecord
|
|
154
144
|
|
155
145
|
scope.unscope!(*item.unscope_values)
|
156
146
|
scope.where_clause += item.where_clause
|
157
|
-
scope.order_values
|
147
|
+
scope.order_values = item.order_values | scope.order_values
|
158
148
|
end
|
159
|
-
|
160
|
-
reflection = next_reflection
|
161
149
|
end
|
162
150
|
|
163
151
|
scope
|
@@ -171,9 +159,9 @@ module ActiveRecord
|
|
171
159
|
end
|
172
160
|
end
|
173
161
|
|
174
|
-
def eval_scope(
|
175
|
-
|
176
|
-
|
162
|
+
def eval_scope(reflection, scope, owner)
|
163
|
+
relation = reflection.build_scope(reflection.aliased_table)
|
164
|
+
relation.instance_exec(owner, &scope) || relation
|
177
165
|
end
|
178
166
|
end
|
179
167
|
end
|
@@ -1,26 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
|
-
# = Active Record Belongs To Association
|
3
4
|
module Associations
|
5
|
+
# = Active Record Belongs To Association
|
4
6
|
class BelongsToAssociation < SingularAssociation #:nodoc:
|
5
7
|
def handle_dependency
|
6
|
-
|
8
|
+
return unless load_target
|
9
|
+
|
10
|
+
case options[:dependent]
|
11
|
+
when :destroy
|
12
|
+
target.destroy
|
13
|
+
raise ActiveRecord::Rollback unless target.destroyed?
|
14
|
+
else
|
15
|
+
target.send(options[:dependent])
|
16
|
+
end
|
7
17
|
end
|
8
18
|
|
9
19
|
def replace(record)
|
10
20
|
if record
|
11
21
|
raise_on_type_mismatch!(record)
|
12
22
|
update_counters_on_replace(record)
|
13
|
-
replace_keys(record)
|
14
23
|
set_inverse_instance(record)
|
15
24
|
@updated = true
|
16
25
|
else
|
17
26
|
decrement_counters
|
18
|
-
remove_keys
|
19
27
|
end
|
20
28
|
|
29
|
+
replace_keys(record)
|
30
|
+
|
21
31
|
self.target = record
|
22
32
|
end
|
23
33
|
|
34
|
+
def inversed_from(record)
|
35
|
+
replace_keys(record)
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
24
39
|
def default(&block)
|
25
40
|
writer(owner.instance_exec(&block)) if reader.nil?
|
26
41
|
end
|
@@ -42,6 +57,10 @@ module ActiveRecord
|
|
42
57
|
update_counters(1)
|
43
58
|
end
|
44
59
|
|
60
|
+
def target_changed?
|
61
|
+
owner.saved_change_to_attribute?(reflection.foreign_key)
|
62
|
+
end
|
63
|
+
|
45
64
|
private
|
46
65
|
|
47
66
|
def update_counters(by)
|
@@ -65,22 +84,22 @@ module ActiveRecord
|
|
65
84
|
def update_counters_on_replace(record)
|
66
85
|
if require_counter_update? && different_target?(record)
|
67
86
|
owner.instance_variable_set :@_after_replace_counter_called, true
|
68
|
-
record.increment!(reflection.counter_cache_column)
|
87
|
+
record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
|
69
88
|
decrement_counters
|
70
89
|
end
|
71
90
|
end
|
72
91
|
|
73
92
|
# Checks whether record is different to the current target, without loading it
|
74
93
|
def different_target?(record)
|
75
|
-
record.
|
94
|
+
record._read_attribute(primary_key(record)) != owner._read_attribute(reflection.foreign_key)
|
76
95
|
end
|
77
96
|
|
78
97
|
def replace_keys(record)
|
79
|
-
owner[reflection.foreign_key] = record._read_attribute(
|
98
|
+
owner[reflection.foreign_key] = record ? record._read_attribute(primary_key(record)) : nil
|
80
99
|
end
|
81
100
|
|
82
|
-
def
|
83
|
-
|
101
|
+
def primary_key(record)
|
102
|
+
reflection.association_primary_key(record.class)
|
84
103
|
end
|
85
104
|
|
86
105
|
def foreign_key_present?
|
@@ -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)
|