activerecord 8.0.0.beta1 → 8.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +67 -0
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/attribute_methods/primary_key.rb +2 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +8 -2
- data/lib/active_record/connection_adapters/abstract_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +4 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +8 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +0 -2
- data/lib/active_record/connection_adapters.rb +0 -56
- data/lib/active_record/core.rb +14 -11
- data/lib/active_record/enum.rb +54 -72
- data/lib/active_record/fixtures.rb +0 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -11
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/migration.rb +0 -5
- data/lib/active_record/model_schema.rb +2 -3
- data/lib/active_record/query_cache.rb +0 -4
- data/lib/active_record/query_logs.rb +5 -11
- data/lib/active_record/querying.rb +2 -2
- data/lib/active_record/railtie.rb +1 -24
- data/lib/active_record/railties/databases.rake +1 -1
- data/lib/active_record/reflection.rb +14 -19
- data/lib/active_record/relation/calculations.rb +24 -28
- data/lib/active_record/relation/predicate_builder.rb +8 -0
- data/lib/active_record/relation/query_methods.rb +66 -36
- data/lib/active_record/relation.rb +8 -1
- data/lib/active_record/result.rb +10 -9
- data/lib/active_record/table_metadata.rb +1 -3
- data/lib/active_record/tasks/database_tasks.rb +4 -31
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record.rb +0 -45
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/sqlite.rb +25 -0
- metadata +9 -10
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
data/lib/active_record/core.rb
CHANGED
@@ -370,7 +370,7 @@ module ActiveRecord
|
|
370
370
|
end
|
371
371
|
|
372
372
|
def predicate_builder # :nodoc:
|
373
|
-
@predicate_builder ||= PredicateBuilder.new(
|
373
|
+
@predicate_builder ||= PredicateBuilder.new(TableMetadata.new(self, arel_table))
|
374
374
|
end
|
375
375
|
|
376
376
|
def type_caster # :nodoc:
|
@@ -415,10 +415,6 @@ module ActiveRecord
|
|
415
415
|
end
|
416
416
|
end
|
417
417
|
|
418
|
-
def table_metadata
|
419
|
-
TableMetadata.new(self, arel_table)
|
420
|
-
end
|
421
|
-
|
422
418
|
def cached_find_by(keys, values)
|
423
419
|
with_connection do |connection|
|
424
420
|
statement = cached_find_by_statement(connection, keys) { |params|
|
@@ -529,12 +525,7 @@ module ActiveRecord
|
|
529
525
|
|
530
526
|
##
|
531
527
|
def initialize_dup(other) # :nodoc:
|
532
|
-
@attributes =
|
533
|
-
if self.class.composite_primary_key?
|
534
|
-
@primary_key.each { |key| @attributes.reset(key) }
|
535
|
-
else
|
536
|
-
@attributes.reset(@primary_key)
|
537
|
-
end
|
528
|
+
@attributes = init_attributes(other)
|
538
529
|
|
539
530
|
_run_initialize_callbacks
|
540
531
|
|
@@ -546,6 +537,18 @@ module ActiveRecord
|
|
546
537
|
super
|
547
538
|
end
|
548
539
|
|
540
|
+
def init_attributes(_) # :nodoc:
|
541
|
+
attrs = @attributes.deep_dup
|
542
|
+
|
543
|
+
if self.class.composite_primary_key?
|
544
|
+
@primary_key.each { |key| attrs.reset(key) }
|
545
|
+
else
|
546
|
+
attrs.reset(@primary_key)
|
547
|
+
end
|
548
|
+
|
549
|
+
attrs
|
550
|
+
end
|
551
|
+
|
549
552
|
# Populate +coder+ with attributes about this record that should be
|
550
553
|
# serialized. The structure of +coder+ defined in this method is
|
551
554
|
# guaranteed to match the structure of +coder+ passed to the #init_with
|
data/lib/active_record/enum.rb
CHANGED
@@ -213,95 +213,77 @@ module ActiveRecord
|
|
213
213
|
attr_reader :name, :mapping
|
214
214
|
end
|
215
215
|
|
216
|
-
def enum(name
|
217
|
-
|
218
|
-
|
219
|
-
return _enum(name, values, **options)
|
220
|
-
end
|
221
|
-
|
222
|
-
definitions = options.slice!(:_prefix, :_suffix, :_scopes, :_default, :_instance_methods)
|
223
|
-
options.transform_keys! { |key| :"#{key[1..-1]}" }
|
224
|
-
|
225
|
-
definitions.each { |name, values| _enum(name, values, **options) }
|
226
|
-
|
227
|
-
ActiveRecord.deprecator.warn(<<~MSG)
|
228
|
-
Defining enums with keyword arguments is deprecated and will be removed
|
229
|
-
in Rails 8.0. Positional arguments should be used instead:
|
216
|
+
def enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
|
217
|
+
assert_valid_enum_definition_values(values)
|
218
|
+
assert_valid_enum_options(options)
|
230
219
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
private
|
236
|
-
def inherited(base)
|
237
|
-
base.defined_enums = defined_enums.deep_dup
|
238
|
-
super
|
239
|
-
end
|
220
|
+
# statuses = { }
|
221
|
+
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
222
|
+
name = name.to_s
|
240
223
|
|
241
|
-
def
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
246
|
-
name = name.to_s
|
224
|
+
# def self.statuses() statuses end
|
225
|
+
detect_enum_conflict!(name, name.pluralize, true)
|
226
|
+
singleton_class.define_method(name.pluralize) { enum_values }
|
227
|
+
defined_enums[name] = enum_values
|
247
228
|
|
248
|
-
|
249
|
-
|
250
|
-
singleton_class.define_method(name.pluralize) { enum_values }
|
251
|
-
defined_enums[name] = enum_values
|
229
|
+
detect_enum_conflict!(name, name)
|
230
|
+
detect_enum_conflict!(name, "#{name}=")
|
252
231
|
|
253
|
-
|
254
|
-
detect_enum_conflict!(name, "#{name}=")
|
232
|
+
attribute(name, **options)
|
255
233
|
|
256
|
-
|
234
|
+
decorate_attributes([name]) do |_name, subtype|
|
235
|
+
if subtype == ActiveModel::Type.default_value
|
236
|
+
raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
|
237
|
+
" backed by a database column or declared with an explicit type" \
|
238
|
+
" via `attribute`."
|
239
|
+
end
|
257
240
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
" backed by a database column or declared with an explicit type" \
|
262
|
-
" via `attribute`."
|
263
|
-
end
|
241
|
+
subtype = subtype.subtype if EnumType === subtype
|
242
|
+
EnumType.new(name, enum_values, subtype, raise_on_invalid_values: !validate)
|
243
|
+
end
|
264
244
|
|
265
|
-
|
266
|
-
|
245
|
+
value_method_names = []
|
246
|
+
_enum_methods_module.module_eval do
|
247
|
+
prefix = if prefix
|
248
|
+
prefix == true ? "#{name}_" : "#{prefix}_"
|
267
249
|
end
|
268
250
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
prefix == true ? "#{name}_" : "#{prefix}_"
|
273
|
-
end
|
274
|
-
|
275
|
-
suffix = if suffix
|
276
|
-
suffix == true ? "_#{name}" : "_#{suffix}"
|
277
|
-
end
|
251
|
+
suffix = if suffix
|
252
|
+
suffix == true ? "_#{name}" : "_#{suffix}"
|
253
|
+
end
|
278
254
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
255
|
+
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
|
256
|
+
pairs.each do |label, value|
|
257
|
+
enum_values[label] = value
|
258
|
+
label = label.to_s
|
283
259
|
|
284
|
-
|
285
|
-
|
286
|
-
|
260
|
+
value_method_name = "#{prefix}#{label}#{suffix}"
|
261
|
+
value_method_names << value_method_name
|
262
|
+
define_enum_methods(name, value_method_name, value, scopes, instance_methods)
|
287
263
|
|
288
|
-
|
289
|
-
|
264
|
+
method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
|
265
|
+
value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
|
290
266
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
end
|
267
|
+
if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
|
268
|
+
value_method_names << value_method_alias
|
269
|
+
define_enum_methods(name, value_method_alias, value, scopes, instance_methods)
|
295
270
|
end
|
296
271
|
end
|
297
|
-
|
272
|
+
end
|
273
|
+
detect_negative_enum_conditions!(value_method_names) if scopes
|
298
274
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
275
|
+
if validate
|
276
|
+
validate = {} unless Hash === validate
|
277
|
+
validates_inclusion_of name, in: enum_values.keys, **validate
|
278
|
+
end
|
279
|
+
|
280
|
+
enum_values.freeze
|
281
|
+
end
|
303
282
|
|
304
|
-
|
283
|
+
private
|
284
|
+
def inherited(base)
|
285
|
+
base.defined_enums = defined_enums.deep_dup
|
286
|
+
super
|
305
287
|
end
|
306
288
|
|
307
289
|
class EnumMethods < Module # :nodoc:
|
@@ -9,7 +9,7 @@ module ActiveRecord
|
|
9
9
|
# it was opened, an ActiveRecord::StaleObjectError exception is thrown if that has occurred
|
10
10
|
# and the update is ignored.
|
11
11
|
#
|
12
|
-
# Check out
|
12
|
+
# Check out ActiveRecord::Locking::Pessimistic for an alternative.
|
13
13
|
#
|
14
14
|
# == Usage
|
15
15
|
#
|
@@ -126,18 +126,12 @@ module ActiveRecord
|
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
return frame if frame
|
134
|
-
end
|
135
|
-
nil
|
136
|
-
end
|
137
|
-
else
|
138
|
-
def query_source_location
|
139
|
-
backtrace_cleaner.clean(caller(1).lazy).first
|
129
|
+
def query_source_location
|
130
|
+
Thread.each_caller_location do |location|
|
131
|
+
frame = backtrace_cleaner.clean_frame(location)
|
132
|
+
return frame if frame
|
140
133
|
end
|
134
|
+
nil
|
141
135
|
end
|
142
136
|
|
143
137
|
def filter(name, value)
|
@@ -25,7 +25,10 @@ module ActiveRecord
|
|
25
25
|
payload = [attributes_for_database, new_record?]
|
26
26
|
|
27
27
|
cached_associations = self.class.reflect_on_all_associations.select do |reflection|
|
28
|
-
association_cached?(reflection.name)
|
28
|
+
if association_cached?(reflection.name)
|
29
|
+
association = association(reflection.name)
|
30
|
+
association.loaded? || association.target.present?
|
31
|
+
end
|
29
32
|
end
|
30
33
|
|
31
34
|
unless cached_associations.empty?
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "set"
|
4
3
|
require "active_support/core_ext/array/access"
|
5
4
|
require "active_support/core_ext/enumerable"
|
6
5
|
require "active_support/core_ext/module/attribute_accessors"
|
@@ -679,10 +678,6 @@ module ActiveRecord
|
|
679
678
|
paths = all_configs.flat_map { |config| config.migrations_paths || Migrator.migrations_paths }.uniq
|
680
679
|
@file_watcher.new([], paths.index_with(["rb"]), &block)
|
681
680
|
end
|
682
|
-
|
683
|
-
def connection
|
684
|
-
ActiveRecord::Tasks::DatabaseTasks.migration_connection
|
685
|
-
end
|
686
681
|
end
|
687
682
|
|
688
683
|
class << self
|
@@ -276,15 +276,14 @@ module ActiveRecord
|
|
276
276
|
end
|
277
277
|
|
278
278
|
@table_name = value
|
279
|
-
@quoted_table_name = nil
|
280
279
|
@arel_table = nil
|
281
280
|
@sequence_name = nil unless @explicit_sequence_name
|
282
281
|
@predicate_builder = nil
|
283
282
|
end
|
284
283
|
|
285
|
-
# Returns a quoted version of the table name
|
284
|
+
# Returns a quoted version of the table name.
|
286
285
|
def quoted_table_name
|
287
|
-
|
286
|
+
adapter_class.quote_table_name(table_name)
|
288
287
|
end
|
289
288
|
|
290
289
|
# Computes the table name, (re)sets it internally, and returns it.
|
@@ -43,10 +43,6 @@ module ActiveRecord
|
|
43
43
|
pool.disable_query_cache!
|
44
44
|
pool.clear_query_cache
|
45
45
|
end
|
46
|
-
|
47
|
-
ActiveRecord::Base.connection_handler.each_connection_pool do |pool|
|
48
|
-
pool.release_connection if pool.active_connection? && !pool.lease_connection.transaction_open?
|
49
|
-
end
|
50
46
|
end
|
51
47
|
|
52
48
|
def self.install_executor_hooks(executor = ActiveSupport::Executor)
|
@@ -152,18 +152,12 @@ module ActiveRecord
|
|
152
152
|
self.cached_comment = nil
|
153
153
|
end
|
154
154
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
return frame if frame
|
160
|
-
end
|
161
|
-
nil
|
162
|
-
end
|
163
|
-
else
|
164
|
-
def query_source_location # :nodoc:
|
165
|
-
LogSubscriber.backtrace_cleaner.clean(caller_locations(1).each).first
|
155
|
+
def query_source_location # :nodoc:
|
156
|
+
Thread.each_caller_location do |location|
|
157
|
+
frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
|
158
|
+
return frame if frame
|
166
159
|
end
|
160
|
+
nil
|
167
161
|
end
|
168
162
|
|
169
163
|
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
|
@@ -86,10 +86,10 @@ module ActiveRecord
|
|
86
86
|
|
87
87
|
message_bus.instrument("instantiation.active_record", payload) do
|
88
88
|
if result_set.includes_column?(inheritance_column)
|
89
|
-
result_set.map { |record| instantiate(record, column_types, &block) }
|
89
|
+
result_set.indexed_rows.map { |record| instantiate(record, column_types, &block) }
|
90
90
|
else
|
91
91
|
# Instantiate a homogeneous set
|
92
|
-
result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
|
92
|
+
result_set.indexed_rows.map { |record| instantiate_instance_of(self, record, column_types, &block) }
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
@@ -184,30 +184,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
-
initializer "active_record.warn_on_records_fetched_greater_than" do
|
188
|
-
if config.active_record.warn_on_records_fetched_greater_than
|
189
|
-
ActiveRecord.deprecator.warn <<~MSG.squish
|
190
|
-
`config.active_record.warn_on_records_fetched_greater_than` is deprecated and will be
|
191
|
-
removed in Rails 8.0.
|
192
|
-
Please subscribe to `sql.active_record` notifications and access the row count field to
|
193
|
-
detect large result set sizes.
|
194
|
-
MSG
|
195
|
-
ActiveSupport.on_load(:active_record) do
|
196
|
-
require "active_record/relation/record_fetch_warning"
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
initializer "active_record.sqlite3_deprecated_warning" do
|
202
|
-
if config.active_record.key?(:sqlite3_production_warning)
|
203
|
-
config.active_record.delete(:sqlite3_production_warning)
|
204
|
-
ActiveRecord.deprecator.warn <<~MSG.squish
|
205
|
-
The `config.active_record.sqlite3_production_warning` configuration no longer has any effect
|
206
|
-
and can be safely removed.
|
207
|
-
MSG
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
187
|
initializer "active_record.sqlite3_adapter_strict_strings_by_default" do
|
212
188
|
config.after_initialize do
|
213
189
|
if config.active_record.sqlite3_adapter_strict_strings_by_default
|
@@ -312,6 +288,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
312
288
|
initializer "active_record.set_executor_hooks" do
|
313
289
|
ActiveRecord::QueryCache.install_executor_hooks
|
314
290
|
ActiveRecord::AsynchronousQueriesTracker.install_executor_hooks
|
291
|
+
ActiveRecord::ConnectionAdapters::ConnectionPool.install_executor_hooks
|
315
292
|
end
|
316
293
|
|
317
294
|
initializer "active_record.add_watchable_files" do |app|
|
@@ -176,7 +176,7 @@ db_namespace = namespace :db do
|
|
176
176
|
end
|
177
177
|
|
178
178
|
# desc 'Resets your database using your migrations for the current environment'
|
179
|
-
task reset: ["db:drop", "db:create", "db:migrate"]
|
179
|
+
task reset: ["db:drop", "db:create", "db:schema:dump", "db:migrate"]
|
180
180
|
|
181
181
|
desc 'Run the "up" for a given migration VERSION.'
|
182
182
|
task up: :load_config do
|
@@ -198,7 +198,7 @@ module ActiveRecord
|
|
198
198
|
end
|
199
199
|
|
200
200
|
def join_scope(table, foreign_table, foreign_klass)
|
201
|
-
predicate_builder = predicate_builder(table)
|
201
|
+
predicate_builder = klass.predicate_builder.with(TableMetadata.new(klass, table))
|
202
202
|
scope_chain_items = join_scopes(table, predicate_builder)
|
203
203
|
klass_scope = klass_join_scope(table, predicate_builder)
|
204
204
|
|
@@ -224,7 +224,7 @@ module ActiveRecord
|
|
224
224
|
klass_scope
|
225
225
|
end
|
226
226
|
|
227
|
-
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
227
|
+
def join_scopes(table, predicate_builder = nil, klass = self.klass, record = nil) # :nodoc:
|
228
228
|
if scope
|
229
229
|
[scope_for(build_scope(table, predicate_builder, klass), record)]
|
230
230
|
else
|
@@ -232,7 +232,7 @@ module ActiveRecord
|
|
232
232
|
end
|
233
233
|
end
|
234
234
|
|
235
|
-
def klass_join_scope(table, predicate_builder) # :nodoc:
|
235
|
+
def klass_join_scope(table, predicate_builder = nil) # :nodoc:
|
236
236
|
relation = build_scope(table, predicate_builder)
|
237
237
|
klass.scope_for_association(relation)
|
238
238
|
end
|
@@ -333,12 +333,8 @@ module ActiveRecord
|
|
333
333
|
collect_join_chain
|
334
334
|
end
|
335
335
|
|
336
|
-
def build_scope(table, predicate_builder =
|
337
|
-
Relation.create(
|
338
|
-
klass,
|
339
|
-
table: table,
|
340
|
-
predicate_builder: predicate_builder
|
341
|
-
)
|
336
|
+
def build_scope(table, predicate_builder = nil, klass = self.klass)
|
337
|
+
Relation.create(klass, table:, predicate_builder:)
|
342
338
|
end
|
343
339
|
|
344
340
|
def strict_loading?
|
@@ -357,10 +353,6 @@ module ActiveRecord
|
|
357
353
|
end
|
358
354
|
|
359
355
|
private
|
360
|
-
def predicate_builder(table)
|
361
|
-
PredicateBuilder.new(TableMetadata.new(klass, table))
|
362
|
-
end
|
363
|
-
|
364
356
|
def primary_key(klass)
|
365
357
|
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
366
358
|
end
|
@@ -531,9 +523,9 @@ module ActiveRecord
|
|
531
523
|
@association_foreign_key = nil
|
532
524
|
@association_primary_key = nil
|
533
525
|
if options[:query_constraints]
|
534
|
-
|
535
|
-
Setting `query_constraints:` option on `#{active_record}.#{macro} :#{name}` is
|
536
|
-
To
|
526
|
+
raise ConfigurationError, <<~MSG.squish
|
527
|
+
Setting `query_constraints:` option on `#{active_record}.#{macro} :#{name}` is not allowed.
|
528
|
+
To get the same behavior, use the `foreign_key` option instead.
|
537
529
|
MSG
|
538
530
|
end
|
539
531
|
|
@@ -1070,7 +1062,7 @@ module ActiveRecord
|
|
1070
1062
|
source_reflection.scopes + super
|
1071
1063
|
end
|
1072
1064
|
|
1073
|
-
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
1065
|
+
def join_scopes(table, predicate_builder = nil, klass = self.klass, record = nil) # :nodoc:
|
1074
1066
|
source_reflection.join_scopes(table, predicate_builder, klass, record) + super
|
1075
1067
|
end
|
1076
1068
|
|
@@ -1243,8 +1235,11 @@ module ActiveRecord
|
|
1243
1235
|
@previous_reflection = previous_reflection
|
1244
1236
|
end
|
1245
1237
|
|
1246
|
-
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
1247
|
-
scopes =
|
1238
|
+
def join_scopes(table, predicate_builder = nil, klass = self.klass, record = nil) # :nodoc:
|
1239
|
+
scopes = super
|
1240
|
+
unless @previous_reflection.through_reflection?
|
1241
|
+
scopes += @previous_reflection.join_scopes(table, predicate_builder, klass, record)
|
1242
|
+
end
|
1248
1243
|
scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
|
1249
1244
|
end
|
1250
1245
|
|
@@ -275,10 +275,14 @@ module ActiveRecord
|
|
275
275
|
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
|
276
276
|
# # => [2, 3]
|
277
277
|
#
|
278
|
-
# Comment.joins(:person).pluck(:id, person:
|
279
|
-
# # SELECT comments.id,
|
278
|
+
# Comment.joins(:person).pluck(:id, person: :id)
|
279
|
+
# # SELECT comments.id, person.id FROM comments INNER JOIN people person ON person.id = comments.person_id
|
280
280
|
# # => [[1, 2], [2, 2]]
|
281
281
|
#
|
282
|
+
# Comment.joins(:person).pluck(:id, person: [:id, :name])
|
283
|
+
# # SELECT comments.id, person.id, person.name FROM comments INNER JOIN people person ON person.id = comments.person_id
|
284
|
+
# # => [[1, 2, 'David'], [2, 2, 'David']]
|
285
|
+
#
|
282
286
|
# Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
|
283
287
|
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
284
288
|
# # => ['0', '27761', '173']
|
@@ -307,8 +311,8 @@ module ActiveRecord
|
|
307
311
|
relation.pluck(*column_names)
|
308
312
|
else
|
309
313
|
model.disallow_raw_sql!(flattened_args(column_names))
|
310
|
-
columns = arel_columns(column_names)
|
311
314
|
relation = spawn
|
315
|
+
columns = relation.arel_columns(column_names)
|
312
316
|
relation.select_values = columns
|
313
317
|
result = skip_query_cache_if_necessary do
|
314
318
|
if where_clause.contradiction?
|
@@ -447,10 +451,13 @@ module ActiveRecord
|
|
447
451
|
end
|
448
452
|
|
449
453
|
def aggregate_column(column_name)
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
+
case column_name
|
455
|
+
when Arel::Expressions
|
456
|
+
column_name
|
457
|
+
when :all
|
458
|
+
Arel.star
|
459
|
+
else
|
460
|
+
arel_column(column_name)
|
454
461
|
end
|
455
462
|
end
|
456
463
|
|
@@ -630,27 +637,12 @@ module ActiveRecord
|
|
630
637
|
end
|
631
638
|
|
632
639
|
def select_for_count
|
633
|
-
if select_values.
|
634
|
-
return select_values.first if select_values.one?
|
635
|
-
|
636
|
-
adapter_class = model.adapter_class
|
637
|
-
select_values.map do |field|
|
638
|
-
column = if Arel.arel_node?(field)
|
639
|
-
field
|
640
|
-
else
|
641
|
-
arel_column(field.to_s) do |attr_name|
|
642
|
-
Arel.sql(attr_name)
|
643
|
-
end
|
644
|
-
end
|
645
|
-
|
646
|
-
if column.is_a?(Arel::Nodes::SqlLiteral)
|
647
|
-
column
|
648
|
-
else
|
649
|
-
"#{adapter_class.quote_table_name(column.relation.name)}.#{adapter_class.quote_column_name(column.name)}"
|
650
|
-
end
|
651
|
-
end.join(", ")
|
652
|
-
else
|
640
|
+
if select_values.empty?
|
653
641
|
:all
|
642
|
+
else
|
643
|
+
with_connection do |conn|
|
644
|
+
arel_columns(select_values).map { |column| conn.visitor.compile(column) }.join(", ")
|
645
|
+
end
|
654
646
|
end
|
655
647
|
end
|
656
648
|
|
@@ -673,7 +665,11 @@ module ActiveRecord
|
|
673
665
|
subquery_alias = Arel.sql("subquery_for_count", retryable: true)
|
674
666
|
select_value = operation_over_aggregate_column(column_alias, "count", false)
|
675
667
|
|
676
|
-
|
668
|
+
if column_name == :all
|
669
|
+
relation.unscope(:order).build_subquery(subquery_alias, select_value)
|
670
|
+
else
|
671
|
+
relation.build_subquery(subquery_alias, select_value)
|
672
|
+
end
|
677
673
|
end
|
678
674
|
end
|
679
675
|
end
|
@@ -72,7 +72,15 @@ module ActiveRecord
|
|
72
72
|
table.associated_table(table_name, &block).arel_table[column_name]
|
73
73
|
end
|
74
74
|
|
75
|
+
def with(table)
|
76
|
+
other = dup
|
77
|
+
other.table = table
|
78
|
+
other
|
79
|
+
end
|
80
|
+
|
75
81
|
protected
|
82
|
+
attr_writer :table
|
83
|
+
|
76
84
|
def expand_from_hash(attributes, &block)
|
77
85
|
return ["1=0"] if attributes.empty?
|
78
86
|
|