activerecord 5.1.0 → 5.2.3
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 +5 -5
- data/CHANGELOG.md +596 -450
- 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.rb +11 -4
- data/lib/active_record/aggregations.rb +6 -5
- data/lib/active_record/association_relation.rb +7 -5
- data/lib/active_record/associations.rb +77 -85
- data/lib/active_record/associations/alias_tracker.rb +23 -32
- data/lib/active_record/associations/association.rb +49 -35
- data/lib/active_record/associations/association_scope.rb +55 -55
- data/lib/active_record/associations/belongs_to_association.rb +30 -11
- 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 +21 -8
- 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 +66 -53
- data/lib/active_record/associations/collection_proxy.rb +30 -73
- data/lib/active_record/associations/foreign_association.rb +2 -0
- data/lib/active_record/associations/has_many_association.rb +13 -2
- data/lib/active_record/associations/has_many_through_association.rb +37 -19
- data/lib/active_record/associations/has_one_association.rb +14 -1
- data/lib/active_record/associations/has_one_through_association.rb +13 -8
- data/lib/active_record/associations/join_dependency.rb +52 -96
- data/lib/active_record/associations/join_dependency/join_association.rb +22 -75
- 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/preloader.rb +17 -37
- data/lib/active_record/associations/preloader/association.rb +53 -92
- data/lib/active_record/associations/preloader/through_association.rb +72 -73
- data/lib/active_record/associations/singular_association.rb +14 -16
- data/lib/active_record/associations/through_association.rb +27 -12
- data/lib/active_record/attribute_assignment.rb +2 -5
- data/lib/active_record/attribute_decorators.rb +3 -2
- data/lib/active_record/attribute_methods.rb +65 -24
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
- data/lib/active_record/attribute_methods/dirty.rb +33 -216
- data/lib/active_record/attribute_methods/primary_key.rb +10 -13
- 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 +22 -19
- data/lib/active_record/attributes.rb +7 -6
- data/lib/active_record/autosave_association.rb +15 -13
- 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 +15 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +120 -39
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +192 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -25
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +65 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +158 -87
- data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
- data/lib/active_record/connection_adapters/abstract_adapter.rb +86 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +126 -189
- data/lib/active_record/connection_adapters/column.rb +4 -2
- data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -15
- 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 -23
- 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 +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -32
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
- 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 -11
- 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/quoting.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +258 -129
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -87
- 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 +24 -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 +90 -96
- 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 +41 -61
- 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 +18 -13
- data/lib/active_record/errors.rb +60 -15
- 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 +10 -7
- data/lib/active_record/log_subscriber.rb +46 -4
- data/lib/active_record/migration.rb +189 -139
- data/lib/active_record/migration/command_recorder.rb +11 -9
- data/lib/active_record/migration/compatibility.rb +81 -29
- data/lib/active_record/migration/join_table.rb +2 -0
- data/lib/active_record/model_schema.rb +74 -58
- 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 +199 -54
- data/lib/active_record/query_cache.rb +8 -10
- data/lib/active_record/querying.rb +5 -3
- data/lib/active_record/railtie.rb +62 -6
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +2 -0
- data/lib/active_record/railties/databases.rake +48 -38
- data/lib/active_record/readonly_attributes.rb +3 -2
- data/lib/active_record/reflection.rb +137 -207
- data/lib/active_record/relation.rb +132 -207
- data/lib/active_record/relation/batches.rb +32 -17
- data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
- data/lib/active_record/relation/calculations.rb +66 -25
- data/lib/active_record/relation/delegation.rb +45 -29
- data/lib/active_record/relation/finder_methods.rb +76 -85
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +53 -23
- data/lib/active_record/relation/predicate_builder.rb +60 -79
- 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/query_attribute.rb +28 -2
- data/lib/active_record/relation/query_methods.rb +135 -103
- data/lib/active_record/relation/record_fetch_warning.rb +2 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +65 -67
- data/lib/active_record/relation/where_clause_factory.rb +5 -48
- 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.rb +12 -10
- data/lib/active_record/scoping/default.rb +10 -7
- data/lib/active_record/scoping/named.rb +40 -12
- 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 +38 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +11 -50
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -3
- 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.rb +4 -1
- 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_caster.rb +2 -0
- data/lib/active_record/type_caster/connection.rb +2 -0
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/validations.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/version.rb +2 -0
- data/lib/rails/generators/active_record.rb +3 -1
- 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.rb +2 -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/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
- metadata +24 -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.rb +0 -240
- data/lib/active_record/attribute/user_provided_default.rb +0 -30
- data/lib/active_record/attribute_mutation_tracker.rb +0 -113
- data/lib/active_record/attribute_set.rb +0 -113
- 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/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 -33
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Querying
|
3
5
|
delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :none?, :one?, to: :all
|
@@ -5,10 +7,10 @@ module ActiveRecord
|
|
5
7
|
delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
|
6
8
|
delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
|
7
9
|
delegate :find_by, :find_by!, to: :all
|
8
|
-
delegate :
|
10
|
+
delegate :destroy_all, :delete_all, :update_all, to: :all
|
9
11
|
delegate :find_each, :find_in_batches, :in_batches, to: :all
|
10
12
|
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
|
11
|
-
:where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly,
|
13
|
+
:where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :extending,
|
12
14
|
:having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all
|
13
15
|
delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
|
14
16
|
delegate :pluck, :ids, to: :all
|
@@ -38,7 +40,7 @@ module ActiveRecord
|
|
38
40
|
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
39
41
|
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
|
40
42
|
column_types = result_set.column_types.dup
|
41
|
-
|
43
|
+
attribute_types.each_key { |k| column_types.delete k }
|
42
44
|
message_bus = ActiveSupport::Notifications.instrumenter
|
43
45
|
|
44
46
|
payload = {
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record"
|
2
4
|
require "rails"
|
3
5
|
require "active_model/railtie"
|
@@ -26,6 +28,9 @@ module ActiveRecord
|
|
26
28
|
config.active_record.use_schema_cache_dump = true
|
27
29
|
config.active_record.maintain_test_schema = true
|
28
30
|
|
31
|
+
config.active_record.sqlite3 = ActiveSupport::OrderedOptions.new
|
32
|
+
config.active_record.sqlite3.represent_boolean_as_integer = nil
|
33
|
+
|
29
34
|
config.eager_load_namespaces << ActiveRecord
|
30
35
|
|
31
36
|
rake_tasks do
|
@@ -54,6 +59,7 @@ module ActiveRecord
|
|
54
59
|
console = ActiveSupport::Logger.new(STDERR)
|
55
60
|
Rails.logger.extend ActiveSupport::Logger.broadcast console
|
56
61
|
end
|
62
|
+
ActiveRecord::Base.verbose_query_logs = false
|
57
63
|
end
|
58
64
|
|
59
65
|
runner do
|
@@ -85,12 +91,16 @@ module ActiveRecord
|
|
85
91
|
filename = File.join(app.config.paths["db"].first, "schema_cache.yml")
|
86
92
|
|
87
93
|
if File.file?(filename)
|
94
|
+
current_version = ActiveRecord::Migrator.current_version
|
95
|
+
|
96
|
+
next if current_version.nil?
|
97
|
+
|
88
98
|
cache = YAML.load(File.read(filename))
|
89
|
-
if cache.version ==
|
99
|
+
if cache.version == current_version
|
90
100
|
connection.schema_cache = cache
|
91
101
|
connection_pool.schema_cache = cache.dup
|
92
102
|
else
|
93
|
-
warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{
|
103
|
+
warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
|
94
104
|
end
|
95
105
|
end
|
96
106
|
end
|
@@ -108,7 +118,9 @@ module ActiveRecord
|
|
108
118
|
|
109
119
|
initializer "active_record.set_configs" do |app|
|
110
120
|
ActiveSupport.on_load(:active_record) do
|
111
|
-
app.config.active_record.
|
121
|
+
configs = app.config.active_record.dup
|
122
|
+
configs.delete(:sqlite3)
|
123
|
+
configs.each do |k, v|
|
112
124
|
send "#{k}=", v
|
113
125
|
end
|
114
126
|
end
|
@@ -157,14 +169,58 @@ end_warning
|
|
157
169
|
end
|
158
170
|
|
159
171
|
initializer "active_record.set_executor_hooks" do
|
160
|
-
|
161
|
-
ActiveRecord::QueryCache.install_executor_hooks
|
162
|
-
end
|
172
|
+
ActiveRecord::QueryCache.install_executor_hooks
|
163
173
|
end
|
164
174
|
|
165
175
|
initializer "active_record.add_watchable_files" do |app|
|
166
176
|
path = app.paths["db"].first
|
167
177
|
config.watchable_files.concat ["#{path}/schema.rb", "#{path}/structure.sql"]
|
168
178
|
end
|
179
|
+
|
180
|
+
initializer "active_record.clear_active_connections" do
|
181
|
+
config.after_initialize do
|
182
|
+
ActiveSupport.on_load(:active_record) do
|
183
|
+
# Ideally the application doesn't connect to the database during boot,
|
184
|
+
# but sometimes it does. In case it did, we want to empty out the
|
185
|
+
# connection pools so that a non-database-using process (e.g. a master
|
186
|
+
# process in a forking server model) doesn't retain a needless
|
187
|
+
# connection. If it was needed, the incremental cost of reestablishing
|
188
|
+
# this connection is trivial: the rest of the pool would need to be
|
189
|
+
# populated anyway.
|
190
|
+
|
191
|
+
clear_active_connections!
|
192
|
+
flush_idle_connections!
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
initializer "active_record.check_represent_sqlite3_boolean_as_integer" do
|
198
|
+
config.after_initialize do
|
199
|
+
ActiveSupport.on_load(:active_record_sqlite3adapter) do
|
200
|
+
represent_boolean_as_integer = Rails.application.config.active_record.sqlite3.delete(:represent_boolean_as_integer)
|
201
|
+
unless represent_boolean_as_integer.nil?
|
202
|
+
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = represent_boolean_as_integer
|
203
|
+
end
|
204
|
+
|
205
|
+
unless ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
|
206
|
+
ActiveSupport::Deprecation.warn <<-MSG
|
207
|
+
Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
|
208
|
+
set to false is deprecated. SQLite databases have used 't' and 'f' to serialize
|
209
|
+
boolean values and must have old data converted to 1 and 0 (its native boolean
|
210
|
+
serialization) before setting this flag to true. Conversion can be accomplished
|
211
|
+
by setting up a rake task which runs
|
212
|
+
|
213
|
+
ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
|
214
|
+
ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
|
215
|
+
|
216
|
+
for all models and all boolean columns, after which the flag must be set to
|
217
|
+
true by adding the following to your application.rb file:
|
218
|
+
|
219
|
+
Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
|
220
|
+
MSG
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
169
225
|
end
|
170
226
|
end
|
@@ -1,17 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_record"
|
2
4
|
|
3
5
|
db_namespace = namespace :db do
|
4
6
|
desc "Set the environment value for the database"
|
5
|
-
task "environment:set" =>
|
7
|
+
task "environment:set" => :load_config do
|
6
8
|
ActiveRecord::InternalMetadata.create_table
|
7
|
-
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::
|
9
|
+
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
|
8
10
|
end
|
9
11
|
|
10
|
-
task check_protected_environments:
|
12
|
+
task check_protected_environments: :load_config do
|
11
13
|
ActiveRecord::Tasks::DatabaseTasks.check_protected_environments!
|
12
14
|
end
|
13
15
|
|
14
|
-
task :
|
16
|
+
task load_config: :environment do
|
15
17
|
ActiveRecord::Base.configurations = ActiveRecord::Tasks::DatabaseTasks.database_configuration || {}
|
16
18
|
ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
|
17
19
|
end
|
@@ -54,7 +56,7 @@ db_namespace = namespace :db do
|
|
54
56
|
end
|
55
57
|
|
56
58
|
desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
|
57
|
-
task migrate:
|
59
|
+
task migrate: :load_config do
|
58
60
|
ActiveRecord::Tasks::DatabaseTasks.migrate
|
59
61
|
db_namespace["_dump"].invoke
|
60
62
|
end
|
@@ -76,7 +78,7 @@ db_namespace = namespace :db do
|
|
76
78
|
|
77
79
|
namespace :migrate do
|
78
80
|
# desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
|
79
|
-
task redo:
|
81
|
+
task redo: :load_config do
|
80
82
|
raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
|
81
83
|
|
82
84
|
if ENV["VERSION"]
|
@@ -92,24 +94,33 @@ db_namespace = namespace :db do
|
|
92
94
|
task reset: ["db:drop", "db:create", "db:migrate"]
|
93
95
|
|
94
96
|
# desc 'Runs the "up" for a given migration VERSION.'
|
95
|
-
task up:
|
97
|
+
task up: :load_config do
|
96
98
|
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
+
ActiveRecord::Tasks::DatabaseTasks.check_target_version
|
101
|
+
|
102
|
+
ActiveRecord::Base.connection.migration_context.run(
|
103
|
+
:up,
|
104
|
+
ActiveRecord::Tasks::DatabaseTasks.target_version
|
105
|
+
)
|
100
106
|
db_namespace["_dump"].invoke
|
101
107
|
end
|
102
108
|
|
103
109
|
# desc 'Runs the "down" for a given migration VERSION.'
|
104
|
-
task down:
|
110
|
+
task down: :load_config do
|
105
111
|
raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
|
106
|
-
|
107
|
-
ActiveRecord::
|
112
|
+
|
113
|
+
ActiveRecord::Tasks::DatabaseTasks.check_target_version
|
114
|
+
|
115
|
+
ActiveRecord::Base.connection.migration_context.run(
|
116
|
+
:down,
|
117
|
+
ActiveRecord::Tasks::DatabaseTasks.target_version
|
118
|
+
)
|
108
119
|
db_namespace["_dump"].invoke
|
109
120
|
end
|
110
121
|
|
111
122
|
desc "Display status of migrations"
|
112
|
-
task status:
|
123
|
+
task status: :load_config do
|
113
124
|
unless ActiveRecord::SchemaMigration.table_exists?
|
114
125
|
abort "Schema migrations table does not exist yet."
|
115
126
|
end
|
@@ -118,8 +129,7 @@ db_namespace = namespace :db do
|
|
118
129
|
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
|
119
130
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
120
131
|
puts "-" * 50
|
121
|
-
|
122
|
-
ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
|
132
|
+
ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
|
123
133
|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
124
134
|
end
|
125
135
|
puts
|
@@ -127,16 +137,16 @@ db_namespace = namespace :db do
|
|
127
137
|
end
|
128
138
|
|
129
139
|
desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)."
|
130
|
-
task rollback:
|
140
|
+
task rollback: :load_config do
|
131
141
|
step = ENV["STEP"] ? ENV["STEP"].to_i : 1
|
132
|
-
ActiveRecord::
|
142
|
+
ActiveRecord::Base.connection.migration_context.rollback(step)
|
133
143
|
db_namespace["_dump"].invoke
|
134
144
|
end
|
135
145
|
|
136
146
|
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
137
|
-
task forward:
|
147
|
+
task forward: :load_config do
|
138
148
|
step = ENV["STEP"] ? ENV["STEP"].to_i : 1
|
139
|
-
ActiveRecord::
|
149
|
+
ActiveRecord::Base.connection.migration_context.forward(step)
|
140
150
|
db_namespace["_dump"].invoke
|
141
151
|
end
|
142
152
|
|
@@ -144,12 +154,12 @@ db_namespace = namespace :db do
|
|
144
154
|
task reset: [ "db:drop", "db:setup" ]
|
145
155
|
|
146
156
|
# desc "Retrieves the charset for the current environment's database"
|
147
|
-
task charset:
|
157
|
+
task charset: :load_config do
|
148
158
|
puts ActiveRecord::Tasks::DatabaseTasks.charset_current
|
149
159
|
end
|
150
160
|
|
151
161
|
# desc "Retrieves the collation for the current environment's database"
|
152
|
-
task collation:
|
162
|
+
task collation: :load_config do
|
153
163
|
begin
|
154
164
|
puts ActiveRecord::Tasks::DatabaseTasks.collation_current
|
155
165
|
rescue NoMethodError
|
@@ -158,13 +168,13 @@ db_namespace = namespace :db do
|
|
158
168
|
end
|
159
169
|
|
160
170
|
desc "Retrieves the current schema version number"
|
161
|
-
task version:
|
162
|
-
puts "Current version: #{ActiveRecord::
|
171
|
+
task version: :load_config do
|
172
|
+
puts "Current version: #{ActiveRecord::Base.connection.migration_context.current_version}"
|
163
173
|
end
|
164
174
|
|
165
175
|
# desc "Raises an error if there are pending migrations"
|
166
|
-
task abort_if_pending_migrations:
|
167
|
-
pending_migrations = ActiveRecord::
|
176
|
+
task abort_if_pending_migrations: :load_config do
|
177
|
+
pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
|
168
178
|
|
169
179
|
if pending_migrations.any?
|
170
180
|
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
|
@@ -186,7 +196,7 @@ db_namespace = namespace :db do
|
|
186
196
|
|
187
197
|
namespace :fixtures do
|
188
198
|
desc "Loads fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
|
189
|
-
task load:
|
199
|
+
task load: :load_config do
|
190
200
|
require "active_record/fixtures"
|
191
201
|
|
192
202
|
base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
@@ -208,7 +218,7 @@ db_namespace = namespace :db do
|
|
208
218
|
end
|
209
219
|
|
210
220
|
# desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
|
211
|
-
task identify:
|
221
|
+
task identify: :load_config do
|
212
222
|
require "active_record/fixtures"
|
213
223
|
|
214
224
|
label, id = ENV["LABEL"], ENV["ID"]
|
@@ -219,7 +229,7 @@ db_namespace = namespace :db do
|
|
219
229
|
base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
220
230
|
|
221
231
|
Dir["#{base_dir}/**/*.yml"].each do |file|
|
222
|
-
if data = YAML
|
232
|
+
if data = YAML.load(ERB.new(IO.read(file)).result)
|
223
233
|
data.each_key do |key|
|
224
234
|
key_id = ActiveRecord::FixtureSet.identify(key)
|
225
235
|
|
@@ -234,7 +244,7 @@ db_namespace = namespace :db do
|
|
234
244
|
|
235
245
|
namespace :schema do
|
236
246
|
desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record"
|
237
|
-
task dump:
|
247
|
+
task dump: :load_config do
|
238
248
|
require "active_record/schema_dumper"
|
239
249
|
filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema.rb")
|
240
250
|
File.open(filename, "w:utf-8") do |file|
|
@@ -244,7 +254,7 @@ db_namespace = namespace :db do
|
|
244
254
|
end
|
245
255
|
|
246
256
|
desc "Loads a schema.rb file into the database"
|
247
|
-
task load: [:
|
257
|
+
task load: [:load_config, :check_protected_environments] do
|
248
258
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV["SCHEMA"])
|
249
259
|
end
|
250
260
|
|
@@ -254,14 +264,14 @@ db_namespace = namespace :db do
|
|
254
264
|
|
255
265
|
namespace :cache do
|
256
266
|
desc "Creates a db/schema_cache.yml file."
|
257
|
-
task dump:
|
267
|
+
task dump: :load_config do
|
258
268
|
conn = ActiveRecord::Base.connection
|
259
269
|
filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml")
|
260
270
|
ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(conn, filename)
|
261
271
|
end
|
262
272
|
|
263
273
|
desc "Clears a db/schema_cache.yml file."
|
264
|
-
task clear:
|
274
|
+
task clear: :load_config do
|
265
275
|
filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml")
|
266
276
|
rm_f filename, verbose: false
|
267
277
|
end
|
@@ -271,7 +281,7 @@ db_namespace = namespace :db do
|
|
271
281
|
|
272
282
|
namespace :structure do
|
273
283
|
desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
|
274
|
-
task dump:
|
284
|
+
task dump: :load_config do
|
275
285
|
filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
|
276
286
|
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
|
277
287
|
ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
|
@@ -286,7 +296,7 @@ db_namespace = namespace :db do
|
|
286
296
|
end
|
287
297
|
|
288
298
|
desc "Recreates the databases from the structure.sql file"
|
289
|
-
task load: [:
|
299
|
+
task load: [:load_config, :check_protected_environments] do
|
290
300
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV["SCHEMA"])
|
291
301
|
end
|
292
302
|
|
@@ -311,7 +321,7 @@ db_namespace = namespace :db do
|
|
311
321
|
begin
|
312
322
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
313
323
|
ActiveRecord::Schema.verbose = false
|
314
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :ruby, ENV["SCHEMA"]
|
324
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :ruby, ENV["SCHEMA"], "test"
|
315
325
|
ensure
|
316
326
|
if should_reconnect
|
317
327
|
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
|
@@ -321,16 +331,16 @@ db_namespace = namespace :db do
|
|
321
331
|
|
322
332
|
# desc "Recreate the test database from an existent structure.sql file"
|
323
333
|
task load_structure: %w(db:test:purge) do
|
324
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :sql, ENV["SCHEMA"]
|
334
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations["test"], :sql, ENV["SCHEMA"], "test"
|
325
335
|
end
|
326
336
|
|
327
337
|
# desc "Empty the test database"
|
328
|
-
task purge: %w(
|
338
|
+
task purge: %w(load_config check_protected_environments) do
|
329
339
|
ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations["test"]
|
330
340
|
end
|
331
341
|
|
332
342
|
# desc 'Load the test schema'
|
333
|
-
task prepare:
|
343
|
+
task prepare: :load_config do
|
334
344
|
unless ActiveRecord::Base.configurations.blank?
|
335
345
|
db_namespace["test:load"].invoke
|
336
346
|
end
|
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ReadonlyAttributes
|
3
5
|
extend ActiveSupport::Concern
|
4
6
|
|
5
7
|
included do
|
6
|
-
class_attribute :_attr_readonly, instance_accessor: false
|
7
|
-
self._attr_readonly = []
|
8
|
+
class_attribute :_attr_readonly, instance_accessor: false, default: []
|
8
9
|
end
|
9
10
|
|
10
11
|
module ClassMethods
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "active_support/core_ext/string/filters"
|
3
|
-
require "
|
4
|
+
require "concurrent/map"
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
# = Active Record Reflection
|
@@ -8,10 +9,8 @@ module ActiveRecord
|
|
8
9
|
extend ActiveSupport::Concern
|
9
10
|
|
10
11
|
included do
|
11
|
-
class_attribute :_reflections, instance_writer: false
|
12
|
-
class_attribute :aggregate_reflections, instance_writer: false
|
13
|
-
self._reflections = {}
|
14
|
-
self.aggregate_reflections = {}
|
12
|
+
class_attribute :_reflections, instance_writer: false, default: {}
|
13
|
+
class_attribute :aggregate_reflections, instance_writer: false, default: {}
|
15
14
|
end
|
16
15
|
|
17
16
|
def self.create(macro, name, scope, options, ar)
|
@@ -35,7 +34,8 @@ module ActiveRecord
|
|
35
34
|
|
36
35
|
def self.add_reflection(ar, name, reflection)
|
37
36
|
ar.clear_reflections_cache
|
38
|
-
|
37
|
+
name = name.to_s
|
38
|
+
ar._reflections = ar._reflections.except(name).merge!(name => reflection)
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.add_aggregate_reflection(ar, name, reflection)
|
@@ -138,7 +138,7 @@ module ActiveRecord
|
|
138
138
|
# HasAndBelongsToManyReflection
|
139
139
|
# ThroughReflection
|
140
140
|
# PolymorphicReflection
|
141
|
-
#
|
141
|
+
# RuntimeReflection
|
142
142
|
class AbstractReflection # :nodoc:
|
143
143
|
def through_reflection?
|
144
144
|
false
|
@@ -154,14 +154,6 @@ module ActiveRecord
|
|
154
154
|
klass.new(attributes, &block)
|
155
155
|
end
|
156
156
|
|
157
|
-
def quoted_table_name
|
158
|
-
klass.quoted_table_name
|
159
|
-
end
|
160
|
-
|
161
|
-
def primary_key_type
|
162
|
-
klass.type_for_attribute(klass.primary_key)
|
163
|
-
end
|
164
|
-
|
165
157
|
# Returns the class name for the macro.
|
166
158
|
#
|
167
159
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
|
@@ -173,7 +165,7 @@ module ActiveRecord
|
|
173
165
|
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
174
166
|
|
175
167
|
def join_keys
|
176
|
-
get_join_keys
|
168
|
+
@join_keys ||= get_join_keys(klass)
|
177
169
|
end
|
178
170
|
|
179
171
|
# Returns a list of scopes that should be applied for this Reflection
|
@@ -182,37 +174,46 @@ module ActiveRecord
|
|
182
174
|
scope ? [scope] : []
|
183
175
|
end
|
184
176
|
|
185
|
-
def
|
186
|
-
|
177
|
+
def build_join_constraint(table, foreign_table)
|
178
|
+
key = join_keys.key
|
179
|
+
foreign_key = join_keys.foreign_key
|
180
|
+
|
181
|
+
constraint = table[key].eq(foreign_table[foreign_key])
|
182
|
+
|
183
|
+
if klass.finder_needs_type_condition?
|
184
|
+
table.create_and([constraint, klass.send(:type_condition, table)])
|
185
|
+
else
|
186
|
+
constraint
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def join_scope(table, foreign_klass)
|
191
|
+
predicate_builder = predicate_builder(table)
|
192
|
+
scope_chain_items = join_scopes(table, predicate_builder)
|
193
|
+
klass_scope = klass_join_scope(table, predicate_builder)
|
194
|
+
|
195
|
+
if type
|
196
|
+
klass_scope.where!(type => foreign_klass.polymorphic_name)
|
197
|
+
end
|
198
|
+
|
199
|
+
scope_chain_items.inject(klass_scope, &:merge!)
|
187
200
|
end
|
188
|
-
deprecate :scope_chain
|
189
201
|
|
190
202
|
def join_scopes(table, predicate_builder) # :nodoc:
|
191
203
|
if scope
|
192
|
-
[
|
193
|
-
.instance_exec(&scope)]
|
204
|
+
[scope_for(build_scope(table, predicate_builder))]
|
194
205
|
else
|
195
206
|
[]
|
196
207
|
end
|
197
208
|
end
|
198
209
|
|
199
210
|
def klass_join_scope(table, predicate_builder) # :nodoc:
|
200
|
-
|
201
|
-
|
202
|
-
scope.joins_values = []
|
203
|
-
}
|
204
|
-
else
|
205
|
-
relation = ActiveRecord::Relation.create(
|
206
|
-
klass,
|
207
|
-
table,
|
208
|
-
predicate_builder,
|
209
|
-
)
|
210
|
-
klass.send(:build_default_scope, relation)
|
211
|
-
end
|
211
|
+
relation = build_scope(table, predicate_builder)
|
212
|
+
klass.scope_for_association(relation)
|
212
213
|
end
|
213
214
|
|
214
215
|
def constraints
|
215
|
-
chain.
|
216
|
+
chain.flat_map(&:scopes)
|
216
217
|
end
|
217
218
|
|
218
219
|
def counter_cache_column
|
@@ -286,17 +287,37 @@ module ActiveRecord
|
|
286
287
|
end
|
287
288
|
|
288
289
|
def get_join_keys(association_klass)
|
289
|
-
JoinKeys.new(
|
290
|
+
JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
|
290
291
|
end
|
291
292
|
|
292
|
-
|
293
|
+
def build_scope(table, predicate_builder = predicate_builder(table))
|
294
|
+
Relation.create(
|
295
|
+
klass,
|
296
|
+
table: table,
|
297
|
+
predicate_builder: predicate_builder
|
298
|
+
)
|
299
|
+
end
|
300
|
+
|
301
|
+
def join_primary_key(*)
|
302
|
+
foreign_key
|
303
|
+
end
|
304
|
+
|
305
|
+
def join_foreign_key
|
306
|
+
active_record_primary_key
|
307
|
+
end
|
293
308
|
|
294
|
-
|
295
|
-
|
309
|
+
protected
|
310
|
+
def actual_source_reflection # FIXME: this is a horrible name
|
311
|
+
self
|
296
312
|
end
|
297
313
|
|
298
|
-
|
299
|
-
|
314
|
+
private
|
315
|
+
def predicate_builder(table)
|
316
|
+
PredicateBuilder.new(TableMetadata.new(klass, table))
|
317
|
+
end
|
318
|
+
|
319
|
+
def primary_key(klass)
|
320
|
+
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
300
321
|
end
|
301
322
|
end
|
302
323
|
|
@@ -343,6 +364,17 @@ module ActiveRecord
|
|
343
364
|
#
|
344
365
|
# <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
|
345
366
|
# <tt>has_many :clients</tt> returns the Client class
|
367
|
+
#
|
368
|
+
# class Company < ActiveRecord::Base
|
369
|
+
# has_many :clients
|
370
|
+
# end
|
371
|
+
#
|
372
|
+
# Company.reflect_on_association(:clients).klass
|
373
|
+
# # => Client
|
374
|
+
#
|
375
|
+
# <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
|
376
|
+
# a new association object. Use +build_association+ or +create_association+
|
377
|
+
# instead. This allows plugins to hook into association object creation.
|
346
378
|
def klass
|
347
379
|
@klass ||= compute_class(class_name)
|
348
380
|
end
|
@@ -361,8 +393,8 @@ module ActiveRecord
|
|
361
393
|
active_record == other_aggregation.active_record
|
362
394
|
end
|
363
395
|
|
364
|
-
def scope_for(
|
365
|
-
|
396
|
+
def scope_for(relation, owner = nil)
|
397
|
+
relation.instance_exec(owner, &scope) || relation
|
366
398
|
end
|
367
399
|
|
368
400
|
private
|
@@ -383,23 +415,10 @@ module ActiveRecord
|
|
383
415
|
# Holds all the metadata about an association as it was specified in the
|
384
416
|
# Active Record class.
|
385
417
|
class AssociationReflection < MacroReflection #:nodoc:
|
386
|
-
# Returns the target association's class.
|
387
|
-
#
|
388
|
-
# class Author < ActiveRecord::Base
|
389
|
-
# has_many :books
|
390
|
-
# end
|
391
|
-
#
|
392
|
-
# Author.reflect_on_association(:books).klass
|
393
|
-
# # => Book
|
394
|
-
#
|
395
|
-
# <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
|
396
|
-
# a new association object. Use +build_association+ or +create_association+
|
397
|
-
# instead. This allows plugins to hook into association object creation.
|
398
|
-
def klass
|
399
|
-
@klass ||= compute_class(class_name)
|
400
|
-
end
|
401
|
-
|
402
418
|
def compute_class(name)
|
419
|
+
if polymorphic?
|
420
|
+
raise ArgumentError, "Polymorphic association does not support to compute class."
|
421
|
+
end
|
403
422
|
active_record.send(:compute_type, name)
|
404
423
|
end
|
405
424
|
|
@@ -408,33 +427,22 @@ module ActiveRecord
|
|
408
427
|
|
409
428
|
def initialize(name, scope, options, active_record)
|
410
429
|
super
|
411
|
-
@automatic_inverse_of = nil
|
412
430
|
@type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
|
413
|
-
@foreign_type = options[:foreign_type] || "#{name}_type"
|
431
|
+
@foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
|
414
432
|
@constructable = calculate_constructable(macro, options)
|
415
|
-
@association_scope_cache =
|
416
|
-
@scope_lock = Mutex.new
|
433
|
+
@association_scope_cache = Concurrent::Map.new
|
417
434
|
|
418
435
|
if options[:class_name] && options[:class_name].class == Class
|
419
|
-
|
420
|
-
Passing a class to the `class_name` is deprecated and will raise
|
421
|
-
an ArgumentError in Rails 5.2. It eagerloads more classes than
|
422
|
-
necessary and potentially creates circular dependencies.
|
423
|
-
|
424
|
-
Please pass the class name as a string:
|
425
|
-
`#{macro} :#{name}, class_name: '#{options[:class_name]}'`
|
426
|
-
MSG
|
436
|
+
raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
|
427
437
|
end
|
428
438
|
end
|
429
439
|
|
430
|
-
def association_scope_cache(conn, owner)
|
440
|
+
def association_scope_cache(conn, owner, &block)
|
431
441
|
key = conn.prepared_statements
|
432
442
|
if polymorphic?
|
433
443
|
key = [key, owner._read_attribute(@foreign_type)]
|
434
444
|
end
|
435
|
-
@association_scope_cache
|
436
|
-
@association_scope_cache[key] ||= yield
|
437
|
-
}
|
445
|
+
@association_scope_cache.compute_if_absent(key) { StatementCache.create(conn, &block) }
|
438
446
|
end
|
439
447
|
|
440
448
|
def constructable? # :nodoc:
|
@@ -458,10 +466,6 @@ module ActiveRecord
|
|
458
466
|
options[:primary_key] || primary_key(klass || self.klass)
|
459
467
|
end
|
460
468
|
|
461
|
-
def association_primary_key_type
|
462
|
-
klass.type_for_attribute(association_primary_key.to_s)
|
463
|
-
end
|
464
|
-
|
465
469
|
def active_record_primary_key
|
466
470
|
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
|
467
471
|
end
|
@@ -484,7 +488,7 @@ module ActiveRecord
|
|
484
488
|
alias :check_eager_loadable! :check_preloadable!
|
485
489
|
|
486
490
|
def join_id_for(owner) # :nodoc:
|
487
|
-
owner[
|
491
|
+
owner[join_foreign_key]
|
488
492
|
end
|
489
493
|
|
490
494
|
def through_reflection
|
@@ -567,7 +571,7 @@ module ActiveRecord
|
|
567
571
|
end
|
568
572
|
|
569
573
|
VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
|
570
|
-
INVALID_AUTOMATIC_INVERSE_OPTIONS = [:
|
574
|
+
INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
|
571
575
|
|
572
576
|
def add_as_source(seed)
|
573
577
|
seed
|
@@ -581,11 +585,9 @@ module ActiveRecord
|
|
581
585
|
seed + [self]
|
582
586
|
end
|
583
587
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
self
|
588
|
-
end
|
588
|
+
def extensions
|
589
|
+
Array(options[:extend])
|
590
|
+
end
|
589
591
|
|
590
592
|
private
|
591
593
|
|
@@ -597,12 +599,14 @@ module ActiveRecord
|
|
597
599
|
# If it cannot find a suitable inverse association name, it returns
|
598
600
|
# +nil+.
|
599
601
|
def inverse_name
|
600
|
-
|
601
|
-
@
|
602
|
+
unless defined?(@inverse_name)
|
603
|
+
@inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
|
602
604
|
end
|
605
|
+
|
606
|
+
@inverse_name
|
603
607
|
end
|
604
608
|
|
605
|
-
# returns either
|
609
|
+
# returns either +nil+ or the inverse association name that it finds.
|
606
610
|
def automatic_inverse_of
|
607
611
|
if can_find_inverse_of_automatically?(self)
|
608
612
|
inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
|
@@ -619,20 +623,15 @@ module ActiveRecord
|
|
619
623
|
return inverse_name
|
620
624
|
end
|
621
625
|
end
|
622
|
-
|
623
|
-
false
|
624
626
|
end
|
625
627
|
|
626
628
|
# Checks if the inverse reflection that is returned from the
|
627
629
|
# +automatic_inverse_of+ method is a valid reflection. We must
|
628
630
|
# make sure that the reflection's active_record name matches up
|
629
631
|
# with the current reflection's klass name.
|
630
|
-
#
|
631
|
-
# Note: klass will always be valid because when there's a NameError
|
632
|
-
# from calling +klass+, +reflection+ will already be set to false.
|
633
632
|
def valid_inverse_reflection?(reflection)
|
634
633
|
reflection &&
|
635
|
-
klass
|
634
|
+
klass <= reflection.active_record &&
|
636
635
|
can_find_inverse_of_automatically?(reflection)
|
637
636
|
end
|
638
637
|
|
@@ -640,9 +639,8 @@ module ActiveRecord
|
|
640
639
|
# us from being able to guess the inverse automatically. First, the
|
641
640
|
# <tt>inverse_of</tt> option cannot be set to false. Second, we must
|
642
641
|
# have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
|
643
|
-
# Third, we must not have options such as <tt>:
|
644
|
-
#
|
645
|
-
# inverse association.
|
642
|
+
# Third, we must not have options such as <tt>:foreign_key</tt>
|
643
|
+
# which prevent us from correctly guessing the inverse association.
|
646
644
|
#
|
647
645
|
# Anything with a scope can additionally ruin our attempt at finding an
|
648
646
|
# inverse, so we exclude reflections with scopes.
|
@@ -672,10 +670,6 @@ module ActiveRecord
|
|
672
670
|
def derive_join_table
|
673
671
|
ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
|
674
672
|
end
|
675
|
-
|
676
|
-
def primary_key(klass)
|
677
|
-
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
678
|
-
end
|
679
673
|
end
|
680
674
|
|
681
675
|
class HasManyReflection < AssociationReflection # :nodoc:
|
@@ -690,6 +684,10 @@ module ActiveRecord
|
|
690
684
|
Associations::HasManyAssociation
|
691
685
|
end
|
692
686
|
end
|
687
|
+
|
688
|
+
def association_primary_key(klass = nil)
|
689
|
+
primary_key(klass || self.klass)
|
690
|
+
end
|
693
691
|
end
|
694
692
|
|
695
693
|
class HasOneReflection < AssociationReflection # :nodoc:
|
@@ -725,30 +723,25 @@ module ActiveRecord
|
|
725
723
|
end
|
726
724
|
end
|
727
725
|
|
728
|
-
def
|
729
|
-
|
726
|
+
def join_primary_key(klass = nil)
|
727
|
+
polymorphic? ? association_primary_key(klass) : association_primary_key
|
728
|
+
end
|
729
|
+
|
730
|
+
def join_foreign_key
|
731
|
+
foreign_key
|
730
732
|
end
|
731
733
|
|
732
734
|
private
|
735
|
+
def can_find_inverse_of_automatically?(_)
|
736
|
+
!polymorphic? && super
|
737
|
+
end
|
733
738
|
|
734
739
|
def calculate_constructable(macro, options)
|
735
740
|
!polymorphic?
|
736
741
|
end
|
737
|
-
|
738
|
-
def join_fk
|
739
|
-
foreign_key
|
740
|
-
end
|
741
|
-
|
742
|
-
def join_pk(klass)
|
743
|
-
polymorphic? ? association_primary_key(klass) : association_primary_key
|
744
|
-
end
|
745
742
|
end
|
746
743
|
|
747
744
|
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
|
748
|
-
def initialize(name, scope, options, active_record)
|
749
|
-
super
|
750
|
-
end
|
751
|
-
|
752
745
|
def macro; :has_and_belongs_to_many; end
|
753
746
|
|
754
747
|
def collection?
|
@@ -759,8 +752,7 @@ module ActiveRecord
|
|
759
752
|
# Holds all the metadata about a :through association as it was specified
|
760
753
|
# in the Active Record class.
|
761
754
|
class ThroughReflection < AbstractReflection #:nodoc:
|
762
|
-
|
763
|
-
delegate :foreign_key, :foreign_type, :association_foreign_key,
|
755
|
+
delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
|
764
756
|
:active_record_primary_key, :type, :get_join_keys, to: :source_reflection
|
765
757
|
|
766
758
|
def initialize(delegate_reflection)
|
@@ -851,10 +843,6 @@ module ActiveRecord
|
|
851
843
|
source_reflection.join_scopes(table, predicate_builder) + super
|
852
844
|
end
|
853
845
|
|
854
|
-
def source_type_scope
|
855
|
-
through_reflection.klass.where(foreign_type => options[:source_type])
|
856
|
-
end
|
857
|
-
|
858
846
|
def has_scope?
|
859
847
|
scope || options[:source_type] ||
|
860
848
|
source_reflection.has_scope? ||
|
@@ -875,10 +863,6 @@ module ActiveRecord
|
|
875
863
|
actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
|
876
864
|
end
|
877
865
|
|
878
|
-
def association_primary_key_type
|
879
|
-
klass.type_for_attribute(association_primary_key.to_s)
|
880
|
-
end
|
881
|
-
|
882
866
|
# Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
|
883
867
|
#
|
884
868
|
# class Post < ActiveRecord::Base
|
@@ -923,10 +907,6 @@ module ActiveRecord
|
|
923
907
|
through_reflection.options
|
924
908
|
end
|
925
909
|
|
926
|
-
def join_id_for(owner) # :nodoc:
|
927
|
-
source_reflection.join_id_for(owner)
|
928
|
-
end
|
929
|
-
|
930
910
|
def check_validity!
|
931
911
|
if through_reflection.nil?
|
932
912
|
raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
|
@@ -985,23 +965,23 @@ module ActiveRecord
|
|
985
965
|
collect_join_reflections(seed + [self])
|
986
966
|
end
|
987
967
|
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
else
|
993
|
-
through_reflection.add_as_through a
|
994
|
-
end
|
995
|
-
end
|
996
|
-
|
997
|
-
private
|
968
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
969
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
970
|
+
protected
|
971
|
+
attr_reader :delegate_reflection
|
998
972
|
|
999
973
|
def actual_source_reflection # FIXME: this is a horrible name
|
1000
|
-
source_reflection.
|
974
|
+
source_reflection.actual_source_reflection
|
1001
975
|
end
|
1002
976
|
|
1003
|
-
|
1004
|
-
|
977
|
+
private
|
978
|
+
def collect_join_reflections(seed)
|
979
|
+
a = source_reflection.add_as_source seed
|
980
|
+
if options[:source_type]
|
981
|
+
through_reflection.add_as_polymorphic_through self, a
|
982
|
+
else
|
983
|
+
through_reflection.add_as_through a
|
984
|
+
end
|
1005
985
|
end
|
1006
986
|
|
1007
987
|
def inverse_name; delegate_reflection.send(:inverse_name); end
|
@@ -1018,66 +998,32 @@ module ActiveRecord
|
|
1018
998
|
end
|
1019
999
|
|
1020
1000
|
class PolymorphicReflection < AbstractReflection # :nodoc:
|
1001
|
+
delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
|
1002
|
+
|
1021
1003
|
def initialize(reflection, previous_reflection)
|
1022
1004
|
@reflection = reflection
|
1023
1005
|
@previous_reflection = previous_reflection
|
1024
1006
|
end
|
1025
1007
|
|
1026
|
-
def scopes
|
1027
|
-
scopes = @previous_reflection.scopes
|
1028
|
-
if @previous_reflection.options[:source_type]
|
1029
|
-
scopes + [@previous_reflection.source_type_scope]
|
1030
|
-
else
|
1031
|
-
scopes
|
1032
|
-
end
|
1033
|
-
end
|
1034
|
-
|
1035
1008
|
def join_scopes(table, predicate_builder) # :nodoc:
|
1036
1009
|
scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
|
1037
|
-
|
1038
|
-
scopes + [@previous_reflection.source_type_scope]
|
1039
|
-
else
|
1040
|
-
scopes
|
1041
|
-
end
|
1042
|
-
end
|
1043
|
-
|
1044
|
-
def klass
|
1045
|
-
@reflection.klass
|
1046
|
-
end
|
1047
|
-
|
1048
|
-
def scope
|
1049
|
-
@reflection.scope
|
1050
|
-
end
|
1051
|
-
|
1052
|
-
def table_name
|
1053
|
-
@reflection.table_name
|
1054
|
-
end
|
1055
|
-
|
1056
|
-
def plural_name
|
1057
|
-
@reflection.plural_name
|
1058
|
-
end
|
1059
|
-
|
1060
|
-
def type
|
1061
|
-
@reflection.type
|
1010
|
+
scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
|
1062
1011
|
end
|
1063
1012
|
|
1064
1013
|
def constraints
|
1065
|
-
@reflection.constraints + [
|
1014
|
+
@reflection.constraints + [source_type_scope]
|
1066
1015
|
end
|
1067
1016
|
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
def get_join_keys(association_klass)
|
1075
|
-
@reflection.get_join_keys(association_klass)
|
1076
|
-
end
|
1017
|
+
private
|
1018
|
+
def source_type_scope
|
1019
|
+
type = @previous_reflection.foreign_type
|
1020
|
+
source_type = @previous_reflection.options[:source_type]
|
1021
|
+
lambda { |object| where(type => source_type) }
|
1022
|
+
end
|
1077
1023
|
end
|
1078
1024
|
|
1079
|
-
class RuntimeReflection <
|
1080
|
-
|
1025
|
+
class RuntimeReflection < AbstractReflection # :nodoc:
|
1026
|
+
delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
|
1081
1027
|
|
1082
1028
|
def initialize(reflection, association)
|
1083
1029
|
@reflection = reflection
|
@@ -1088,24 +1034,8 @@ module ActiveRecord
|
|
1088
1034
|
@association.klass
|
1089
1035
|
end
|
1090
1036
|
|
1091
|
-
def
|
1092
|
-
klass.
|
1093
|
-
end
|
1094
|
-
|
1095
|
-
def constraints
|
1096
|
-
@reflection.constraints
|
1097
|
-
end
|
1098
|
-
|
1099
|
-
def source_type_info
|
1100
|
-
@reflection.source_type_info
|
1101
|
-
end
|
1102
|
-
|
1103
|
-
def alias_candidate(name)
|
1104
|
-
"#{plural_name}_#{name}_join"
|
1105
|
-
end
|
1106
|
-
|
1107
|
-
def alias_name
|
1108
|
-
Arel::Table.new(table_name)
|
1037
|
+
def aliased_table
|
1038
|
+
@aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
|
1109
1039
|
end
|
1110
1040
|
|
1111
1041
|
def all_includes; yield; end
|