activerecord 5.2.0.beta2 → 5.2.0.rc1

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.

Files changed (80) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +231 -2
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record.rb +1 -1
  6. data/lib/active_record/aggregations.rb +4 -5
  7. data/lib/active_record/association_relation.rb +2 -2
  8. data/lib/active_record/associations.rb +18 -12
  9. data/lib/active_record/associations/alias_tracker.rb +2 -10
  10. data/lib/active_record/associations/association.rb +1 -1
  11. data/lib/active_record/associations/belongs_to_association.rb +9 -9
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -6
  13. data/lib/active_record/associations/builder/association.rb +2 -2
  14. data/lib/active_record/associations/builder/belongs_to.rb +7 -3
  15. data/lib/active_record/associations/collection_association.rb +2 -2
  16. data/lib/active_record/associations/collection_proxy.rb +1 -1
  17. data/lib/active_record/associations/has_many_association.rb +1 -1
  18. data/lib/active_record/associations/has_many_through_association.rb +4 -17
  19. data/lib/active_record/associations/has_one_through_association.rb +5 -6
  20. data/lib/active_record/associations/preloader.rb +1 -1
  21. data/lib/active_record/associations/preloader/association.rb +2 -2
  22. data/lib/active_record/associations/through_association.rb +22 -9
  23. data/lib/active_record/attribute_methods.rb +1 -5
  24. data/lib/active_record/attribute_methods/dirty.rb +2 -4
  25. data/lib/active_record/attributes.rb +1 -1
  26. data/lib/active_record/autosave_association.rb +3 -0
  27. data/lib/active_record/callbacks.rb +2 -2
  28. data/lib/active_record/collection_cache_key.rb +5 -6
  29. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1 -3
  30. data/lib/active_record/connection_adapters/abstract/database_statements.rb +57 -21
  31. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +1 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +20 -3
  33. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -15
  34. data/lib/active_record/connection_adapters/abstract_adapter.rb +19 -6
  35. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +55 -64
  36. data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -1
  37. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +0 -4
  38. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +21 -6
  39. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
  40. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  41. data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -1
  42. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -0
  43. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +13 -4
  44. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +170 -48
  45. data/lib/active_record/connection_adapters/postgresql_adapter.rb +15 -5
  46. data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
  47. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +63 -18
  48. data/lib/active_record/core.rb +12 -3
  49. data/lib/active_record/enum.rb +2 -0
  50. data/lib/active_record/fixtures.rb +28 -37
  51. data/lib/active_record/gem_version.rb +1 -1
  52. data/lib/active_record/inheritance.rb +3 -4
  53. data/lib/active_record/log_subscriber.rb +41 -0
  54. data/lib/active_record/migration.rb +138 -120
  55. data/lib/active_record/migration/compatibility.rb +20 -0
  56. data/lib/active_record/model_schema.rb +19 -16
  57. data/lib/active_record/persistence.rb +8 -11
  58. data/lib/active_record/railtie.rb +7 -2
  59. data/lib/active_record/railties/databases.rake +8 -11
  60. data/lib/active_record/reflection.rb +10 -13
  61. data/lib/active_record/relation.rb +27 -17
  62. data/lib/active_record/relation/calculations.rb +17 -12
  63. data/lib/active_record/relation/finder_methods.rb +30 -37
  64. data/lib/active_record/relation/merger.rb +30 -2
  65. data/lib/active_record/relation/predicate_builder.rb +12 -0
  66. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -1
  67. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  68. data/lib/active_record/relation/query_methods.rb +14 -24
  69. data/lib/active_record/relation/spawn_methods.rb +1 -1
  70. data/lib/active_record/relation/where_clause.rb +16 -2
  71. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  72. data/lib/active_record/sanitization.rb +130 -128
  73. data/lib/active_record/schema.rb +1 -1
  74. data/lib/active_record/schema_dumper.rb +12 -3
  75. data/lib/active_record/scoping/named.rb +6 -0
  76. data/lib/active_record/store.rb +1 -1
  77. data/lib/active_record/table_metadata.rb +10 -3
  78. data/lib/active_record/tasks/database_tasks.rb +4 -4
  79. data/lib/active_record/type_caster/map.rb +1 -1
  80. metadata +9 -9
@@ -99,7 +99,9 @@ module ActiveRecord
99
99
  # for updating all records in a single query.
100
100
  def update(id = :all, attributes)
101
101
  if id.is_a?(Array)
102
- id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }.compact
102
+ id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
103
+ object.update(attributes[idx])
104
+ }
103
105
  elsif id == :all
104
106
  all.each { |record| record.update(attributes) }
105
107
  else
@@ -112,7 +114,6 @@ module ActiveRecord
112
114
  object.update(attributes)
113
115
  object
114
116
  end
115
- rescue RecordNotFound
116
117
  end
117
118
 
118
119
  # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
@@ -136,11 +137,10 @@ module ActiveRecord
136
137
  # Todo.destroy(todos)
137
138
  def destroy(id)
138
139
  if id.is_a?(Array)
139
- id.map { |one_id| destroy(one_id) }.compact
140
+ find(id).each(&:destroy)
140
141
  else
141
142
  find(id).destroy
142
143
  end
143
- rescue RecordNotFound
144
144
  end
145
145
 
146
146
  # Deletes the row with a primary key matching the +id+ argument, using a
@@ -359,10 +359,10 @@ module ActiveRecord
359
359
  # Any change to the attributes on either instance will affect both instances.
360
360
  # If you want to change the sti column as well, use #becomes! instead.
361
361
  def becomes(klass)
362
- became = klass.new
362
+ became = klass.allocate
363
+ became.send(:initialize)
363
364
  became.instance_variable_set("@attributes", @attributes)
364
365
  became.instance_variable_set("@mutations_from_database", @mutations_from_database) if defined?(@mutations_from_database)
365
- became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
366
366
  became.instance_variable_set("@new_record", new_record?)
367
367
  became.instance_variable_set("@destroyed", destroyed?)
368
368
  became.errors.copy!(errors)
@@ -402,11 +402,7 @@ module ActiveRecord
402
402
  verify_readonly_attribute(name)
403
403
  public_send("#{name}=", value)
404
404
 
405
- if has_changes_to_save?
406
- save(validate: false)
407
- else
408
- true
409
- end
405
+ save(validate: false)
410
406
  end
411
407
 
412
408
  # Updates the attributes of the model from the passed-in hash and saves the
@@ -698,6 +694,7 @@ module ActiveRecord
698
694
 
699
695
  def create_or_update(*args, &block)
700
696
  _raise_readonly_record_error if readonly?
697
+ return false if destroyed?
701
698
  result = new_record? ? _create_record(&block) : _update_record(*args, &block)
702
699
  result != false
703
700
  end
@@ -59,6 +59,7 @@ module ActiveRecord
59
59
  console = ActiveSupport::Logger.new(STDERR)
60
60
  Rails.logger.extend ActiveSupport::Logger.broadcast console
61
61
  end
62
+ ActiveRecord::Base.verbose_query_logs = false
62
63
  end
63
64
 
64
65
  runner do
@@ -90,12 +91,16 @@ module ActiveRecord
90
91
  filename = File.join(app.config.paths["db"].first, "schema_cache.yml")
91
92
 
92
93
  if File.file?(filename)
94
+ current_version = ActiveRecord::Migrator.current_version
95
+
96
+ next if current_version.nil?
97
+
93
98
  cache = YAML.load(File.read(filename))
94
- if cache.version == ActiveRecord::Migrator.current_version
99
+ if cache.version == current_version
95
100
  connection.schema_cache = cache
96
101
  connection_pool.schema_cache = cache.dup
97
102
  else
98
- warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{ActiveRecord::Migrator.current_version}, but the one in the cache is #{cache.version}."
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}."
99
104
  end
100
105
  end
101
106
  end
@@ -6,7 +6,7 @@ db_namespace = namespace :db do
6
6
  desc "Set the environment value for the database"
7
7
  task "environment:set" => :load_config do
8
8
  ActiveRecord::InternalMetadata.create_table
9
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
9
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
10
10
  end
11
11
 
12
12
  task check_protected_environments: :load_config do
@@ -99,9 +99,8 @@ db_namespace = namespace :db do
99
99
 
100
100
  ActiveRecord::Tasks::DatabaseTasks.check_target_version
101
101
 
102
- ActiveRecord::Migrator.run(
102
+ ActiveRecord::Base.connection.migration_context.run(
103
103
  :up,
104
- ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
105
104
  ActiveRecord::Tasks::DatabaseTasks.target_version
106
105
  )
107
106
  db_namespace["_dump"].invoke
@@ -113,9 +112,8 @@ db_namespace = namespace :db do
113
112
 
114
113
  ActiveRecord::Tasks::DatabaseTasks.check_target_version
115
114
 
116
- ActiveRecord::Migrator.run(
115
+ ActiveRecord::Base.connection.migration_context.run(
117
116
  :down,
118
- ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
119
117
  ActiveRecord::Tasks::DatabaseTasks.target_version
120
118
  )
121
119
  db_namespace["_dump"].invoke
@@ -131,8 +129,7 @@ db_namespace = namespace :db do
131
129
  puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
132
130
  puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
133
131
  puts "-" * 50
134
- paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
135
- ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
132
+ ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
136
133
  puts "#{status.center(8)} #{version.ljust(14)} #{name}"
137
134
  end
138
135
  puts
@@ -142,14 +139,14 @@ db_namespace = namespace :db do
142
139
  desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)."
143
140
  task rollback: :load_config do
144
141
  step = ENV["STEP"] ? ENV["STEP"].to_i : 1
145
- ActiveRecord::Migrator.rollback(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step)
142
+ ActiveRecord::Base.connection.migration_context.rollback(step)
146
143
  db_namespace["_dump"].invoke
147
144
  end
148
145
 
149
146
  # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
150
147
  task forward: :load_config do
151
148
  step = ENV["STEP"] ? ENV["STEP"].to_i : 1
152
- ActiveRecord::Migrator.forward(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step)
149
+ ActiveRecord::Base.connection.migration_context.forward(step)
153
150
  db_namespace["_dump"].invoke
154
151
  end
155
152
 
@@ -172,12 +169,12 @@ db_namespace = namespace :db do
172
169
 
173
170
  desc "Retrieves the current schema version number"
174
171
  task version: :load_config do
175
- puts "Current version: #{ActiveRecord::Migrator.current_version}"
172
+ puts "Current version: #{ActiveRecord::Base.connection.migration_context.current_version}"
176
173
  end
177
174
 
178
175
  # desc "Raises an error if there are pending migrations"
179
176
  task abort_if_pending_migrations: :load_config do
180
- pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Tasks::DatabaseTasks.migrations_paths).pending_migrations
177
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
181
178
 
182
179
  if pending_migrations.any?
183
180
  puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
@@ -34,7 +34,8 @@ module ActiveRecord
34
34
 
35
35
  def self.add_reflection(ar, name, reflection)
36
36
  ar.clear_reflections_cache
37
- ar._reflections = ar._reflections.merge(name.to_s => reflection)
37
+ name = name.to_s
38
+ ar._reflections = ar._reflections.except(name).merge!(name => reflection)
38
39
  end
39
40
 
40
41
  def self.add_aggregate_reflection(ar, name, reflection)
@@ -290,10 +291,14 @@ module ActiveRecord
290
291
  end
291
292
 
292
293
  def build_scope(table, predicate_builder = predicate_builder(table))
293
- Relation.create(klass, table, predicate_builder)
294
+ Relation.create(
295
+ klass,
296
+ table: table,
297
+ predicate_builder: predicate_builder
298
+ )
294
299
  end
295
300
 
296
- def join_primary_key(_)
301
+ def join_primary_key(*)
297
302
  foreign_key
298
303
  end
299
304
 
@@ -458,10 +463,6 @@ module ActiveRecord
458
463
  options[:primary_key] || primary_key(klass || self.klass)
459
464
  end
460
465
 
461
- def association_primary_key_type
462
- klass.type_for_attribute(association_primary_key.to_s)
463
- end
464
-
465
466
  def active_record_primary_key
466
467
  @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
467
468
  end
@@ -567,7 +568,7 @@ module ActiveRecord
567
568
  end
568
569
 
569
570
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
570
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :foreign_key]
571
+ INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
571
572
 
572
573
  def add_as_source(seed)
573
574
  seed
@@ -722,7 +723,7 @@ module ActiveRecord
722
723
  end
723
724
  end
724
725
 
725
- def join_primary_key(klass)
726
+ def join_primary_key(klass = nil)
726
727
  polymorphic? ? association_primary_key(klass) : association_primary_key
727
728
  end
728
729
 
@@ -859,10 +860,6 @@ module ActiveRecord
859
860
  actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
860
861
  end
861
862
 
862
- def association_primary_key_type
863
- klass.type_for_attribute(association_primary_key.to_s)
864
- end
865
-
866
863
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
867
864
  #
868
865
  # class Post < ActiveRecord::Base
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
11
11
  :reverse_order, :distinct, :create_with, :skip_query_cache]
12
12
  CLAUSE_METHODS = [:where, :having, :from]
13
- INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
13
+ INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having]
14
14
 
15
15
  VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
16
16
 
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  alias :loaded? :loaded
23
23
  alias :locked? :lock_value
24
24
 
25
- def initialize(klass, table, predicate_builder, values = {})
25
+ def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
26
26
  @klass = klass
27
27
  @table = table
28
28
  @values = values
@@ -52,8 +52,8 @@ module ActiveRecord
52
52
  #
53
53
  # user = users.new { |user| user.name = 'Oscar' }
54
54
  # user.name # => Oscar
55
- def new(*args, &block)
56
- scoping { @klass.new(*args, &block) }
55
+ def new(attributes = nil, &block)
56
+ scoping { klass.new(scope_for_create(attributes), &block) }
57
57
  end
58
58
 
59
59
  alias build new
@@ -77,8 +77,12 @@ module ActiveRecord
77
77
  #
78
78
  # users.create(name: nil) # validation on name
79
79
  # # => #<User id: nil, name: nil, ...>
80
- def create(*args, &block)
81
- scoping { @klass.create(*args, &block) }
80
+ def create(attributes = nil, &block)
81
+ if attributes.is_a?(Array)
82
+ attributes.collect { |attr| create(attr, &block) }
83
+ else
84
+ scoping { klass.create(scope_for_create(attributes), &block) }
85
+ end
82
86
  end
83
87
 
84
88
  # Similar to #create, but calls
@@ -87,8 +91,12 @@ module ActiveRecord
87
91
  #
88
92
  # Expects arguments in the same format as
89
93
  # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!].
90
- def create!(*args, &block)
91
- scoping { @klass.create!(*args, &block) }
94
+ def create!(attributes = nil, &block)
95
+ if attributes.is_a?(Array)
96
+ attributes.collect { |attr| create!(attr, &block) }
97
+ else
98
+ scoping { klass.create!(scope_for_create(attributes), &block) }
99
+ end
92
100
  end
93
101
 
94
102
  def first_or_create(attributes = nil, &block) # :nodoc:
@@ -306,10 +314,10 @@ module ActiveRecord
306
314
 
307
315
  stmt = Arel::UpdateManager.new
308
316
 
309
- stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
317
+ stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates))
310
318
  stmt.table(table)
311
319
 
312
- if has_join_values?
320
+ if has_join_values? || offset_value
313
321
  @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
314
322
  else
315
323
  stmt.key = arel_attribute(primary_key)
@@ -357,8 +365,8 @@ module ActiveRecord
357
365
  #
358
366
  # If an invalid method is supplied, #delete_all raises an ActiveRecordError:
359
367
  #
360
- # Post.limit(100).delete_all
361
- # # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
368
+ # Post.distinct.delete_all
369
+ # # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
362
370
  def delete_all
363
371
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
364
372
  value = get_value(method)
@@ -376,7 +384,7 @@ module ActiveRecord
376
384
  stmt = Arel::DeleteManager.new
377
385
  stmt.from(table)
378
386
 
379
- if has_join_values?
387
+ if has_join_values? || has_limit_or_offset?
380
388
  @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
381
389
  else
382
390
  stmt.wheres = arel.constraints
@@ -422,7 +430,7 @@ module ActiveRecord
422
430
  relation = self
423
431
 
424
432
  if eager_loading?
425
- find_with_associations { |rel, _| relation = rel }
433
+ apply_join_dependency { |rel, _| relation = rel }
426
434
  end
427
435
 
428
436
  conn = klass.connection
@@ -440,8 +448,10 @@ module ActiveRecord
440
448
  where_clause.to_h(relation_table_name)
441
449
  end
442
450
 
443
- def scope_for_create
444
- where_values_hash.merge!(create_with_value.stringify_keys)
451
+ def scope_for_create(attributes = nil)
452
+ scope = where_values_hash.merge!(create_with_value.stringify_keys)
453
+ scope.merge!(attributes) if attributes
454
+ scope
445
455
  end
446
456
 
447
457
  # Returns true if relation needs eager loading.
@@ -523,7 +533,7 @@ module ActiveRecord
523
533
  skip_query_cache_if_necessary do
524
534
  @records =
525
535
  if eager_loading?
526
- find_with_associations do |relation, join_dependency|
536
+ apply_join_dependency do |relation, join_dependency|
527
537
  if ActiveRecord::NullRelation === relation
528
538
  []
529
539
  else
@@ -131,7 +131,14 @@ module ActiveRecord
131
131
  def calculate(operation, column_name)
132
132
  if has_include?(column_name)
133
133
  relation = apply_join_dependency
134
- relation.distinct! if operation.to_s.downcase == "count"
134
+
135
+ if operation.to_s.downcase == "count" && !distinct_value
136
+ relation.distinct!
137
+ # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
138
+ if (column_name == :all || column_name.nil?) && select_values.empty?
139
+ relation.order_values = []
140
+ end
141
+ end
135
142
 
136
143
  relation.calculate(operation, column_name)
137
144
  else
@@ -217,7 +224,7 @@ module ActiveRecord
217
224
  if operation == "count"
218
225
  column_name ||= select_for_count
219
226
  if column_name == :all
220
- if distinct && (group_values.any? || !(has_limit_or_offset? && order_values.any?))
227
+ if distinct && (group_values.any? || select_values.empty? && order_values.empty?)
221
228
  column_name = primary_key
222
229
  end
223
230
  elsif column_name =~ /\s*DISTINCT[\s(]+/i
@@ -235,7 +242,7 @@ module ActiveRecord
235
242
  def aggregate_column(column_name)
236
243
  return column_name if Arel::Expressions === column_name
237
244
 
238
- if @klass.has_attribute?(column_name.to_s) || @klass.attribute_alias?(column_name.to_s)
245
+ if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
239
246
  @klass.arel_attribute(column_name)
240
247
  else
241
248
  Arel.sql(column_name == :all ? "*" : column_name.to_s)
@@ -249,7 +256,7 @@ module ActiveRecord
249
256
  def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
250
257
  column_alias = column_name
251
258
 
252
- if operation == "count" && has_limit_or_offset?
259
+ if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
253
260
  # Shortcut when limit is zero.
254
261
  return 0 if limit_value == 0
255
262
 
@@ -391,14 +398,12 @@ module ActiveRecord
391
398
  end
392
399
 
393
400
  def build_count_subquery(relation, column_name, distinct)
394
- relation.select_values = [
395
- if column_name == :all
396
- distinct ? table[Arel.star] : Arel.sql(FinderMethods::ONE_AS_ONE)
397
- else
398
- column_alias = Arel.sql("count_column")
399
- aggregate_column(column_name).as(column_alias)
400
- end
401
- ]
401
+ if column_name == :all
402
+ relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
403
+ else
404
+ column_alias = Arel.sql("count_column")
405
+ relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
406
+ end
402
407
 
403
408
  subquery = relation.arel.as(Arel.sql("subquery_for_count"))
404
409
  select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
@@ -18,9 +18,10 @@ module ActiveRecord
18
18
  # Person.find([1]) # returns an array for the object with ID = 1
19
19
  # Person.where("administrator = 1").order("created_on DESC").find(1)
20
20
  #
21
- # NOTE: The returned records may not be in the same order as the ids you
22
- # provide since database rows are unordered. You will need to provide an explicit QueryMethods#order
23
- # option if you want the results to be sorted.
21
+ # NOTE: The returned records are in the same order as the ids you provide.
22
+ # If you want the results to be sorted by database, you can use ActiveRecord::QueryMethods#where
23
+ # method and provide an explicit ActiveRecord::QueryMethods#order option.
24
+ # But ActiveRecord::QueryMethods#where method doesn't raise ActiveRecord::RecordNotFound.
24
25
  #
25
26
  # ==== Find with lock
26
27
  #
@@ -147,7 +148,7 @@ module ActiveRecord
147
148
  #
148
149
  # [#<Person id:4>, #<Person id:3>, #<Person id:2>]
149
150
  def last(limit = nil)
150
- return find_last(limit) if loaded? || limit_value
151
+ return find_last(limit) if loaded? || has_limit_or_offset?
151
152
 
152
153
  result = ordered_relation.limit(limit)
153
154
  result = result.reverse_order!
@@ -312,7 +313,7 @@ module ActiveRecord
312
313
  return false if !conditions || limit_value == 0
313
314
 
314
315
  if eager_loading?
315
- relation = apply_join_dependency(construct_join_dependency(eager_loading: false))
316
+ relation = apply_join_dependency(eager_loading: false)
316
317
  return relation.exists?(conditions)
317
318
  end
318
319
 
@@ -357,24 +358,6 @@ module ActiveRecord
357
358
  offset_value || 0
358
359
  end
359
360
 
360
- def find_with_associations
361
- # NOTE: the JoinDependency constructed here needs to know about
362
- # any joins already present in `self`, so pass them in
363
- #
364
- # failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
365
- # incorrect SQL is generated. In that case, the join dependency for
366
- # SpecialCategorizations is constructed without knowledge of the
367
- # preexisting join in joins_values to categorizations (by way of
368
- # the `has_many :through` for categories).
369
- #
370
- join_dependency = construct_join_dependency
371
-
372
- relation = apply_join_dependency(join_dependency)
373
- relation._select!(join_dependency.aliases.columns)
374
-
375
- yield relation, join_dependency
376
- end
377
-
378
361
  def construct_relation_for_exists(conditions)
379
362
  relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
380
363
 
@@ -390,22 +373,29 @@ module ActiveRecord
390
373
 
391
374
  def construct_join_dependency(eager_loading: true)
392
375
  including = eager_load_values + includes_values
376
+ joins = joins_values.select { |join| join.is_a?(Arel::Nodes::Join) }
393
377
  ActiveRecord::Associations::JoinDependency.new(
394
- klass, table, including, alias_tracker(joins_values), eager_loading: eager_loading
378
+ klass, table, including, alias_tracker(joins), eager_loading: eager_loading
395
379
  )
396
380
  end
397
381
 
398
- def apply_join_dependency(join_dependency = construct_join_dependency)
382
+ def apply_join_dependency(eager_loading: true)
383
+ join_dependency = construct_join_dependency(eager_loading: eager_loading)
399
384
  relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
400
385
 
401
- if using_limitable_reflections?(join_dependency.reflections)
402
- relation
403
- else
404
- if relation.limit_value
386
+ if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
387
+ if has_limit_or_offset?
405
388
  limited_ids = limited_ids_for(relation)
406
389
  limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
407
390
  end
408
- relation.except(:limit, :offset)
391
+ relation.limit_value = relation.offset_value = nil
392
+ end
393
+
394
+ if block_given?
395
+ relation._select!(join_dependency.aliases.columns)
396
+ yield relation, join_dependency
397
+ else
398
+ relation
409
399
  end
410
400
  end
411
401
 
@@ -531,7 +521,11 @@ module ActiveRecord
531
521
  else
532
522
  relation = ordered_relation
533
523
 
534
- if limit_value.nil? || index < limit_value
524
+ if limit_value
525
+ limit = [limit_value - index, limit].min
526
+ end
527
+
528
+ if limit > 0
535
529
  relation = relation.offset(offset_index + index) unless index.zero?
536
530
  relation.limit(limit).to_a
537
531
  else
@@ -546,12 +540,11 @@ module ActiveRecord
546
540
  else
547
541
  relation = ordered_relation
548
542
 
549
- relation.to_a[-index]
550
- # TODO: can be made more performant on large result sets by
551
- # for instance, last(index)[-index] (which would require
552
- # refactoring the last(n) finder method to make test suite pass),
553
- # or by using a combination of reverse_order, limit, and offset,
554
- # e.g., reverse_order.offset(index-1).first
543
+ if equal?(relation) || has_limit_or_offset?
544
+ relation.records[-index]
545
+ else
546
+ relation.last(index)[-index]
547
+ end
555
548
  end
556
549
  end
557
550