activerecord 5.0.0 → 5.0.7.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +431 -2
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/aggregations.rb +4 -2
  5. data/lib/active_record/association_relation.rb +4 -1
  6. data/lib/active_record/associations/association.rb +11 -1
  7. data/lib/active_record/associations/association_scope.rb +1 -1
  8. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
  9. data/lib/active_record/associations/builder/singular_association.rb +10 -1
  10. data/lib/active_record/associations/collection_association.rb +56 -48
  11. data/lib/active_record/associations/collection_proxy.rb +38 -20
  12. data/lib/active_record/associations/has_many_association.rb +1 -7
  13. data/lib/active_record/associations/has_many_through_association.rb +2 -4
  14. data/lib/active_record/associations/join_dependency/join_association.rb +6 -11
  15. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  16. data/lib/active_record/associations/join_dependency.rb +10 -4
  17. data/lib/active_record/associations/preloader/association.rb +24 -37
  18. data/lib/active_record/associations/preloader/collection_association.rb +0 -1
  19. data/lib/active_record/associations/preloader/singular_association.rb +0 -1
  20. data/lib/active_record/associations/preloader/through_association.rb +10 -4
  21. data/lib/active_record/associations/singular_association.rb +8 -2
  22. data/lib/active_record/associations/through_association.rb +1 -1
  23. data/lib/active_record/associations.rb +38 -17
  24. data/lib/active_record/attribute.rb +3 -3
  25. data/lib/active_record/attribute_methods/primary_key.rb +14 -1
  26. data/lib/active_record/attribute_methods/read.rb +1 -1
  27. data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -2
  28. data/lib/active_record/attribute_methods.rb +3 -7
  29. data/lib/active_record/attribute_set/builder.rb +37 -13
  30. data/lib/active_record/attribute_set.rb +2 -0
  31. data/lib/active_record/attributes.rb +3 -3
  32. data/lib/active_record/autosave_association.rb +15 -11
  33. data/lib/active_record/base.rb +1 -1
  34. data/lib/active_record/collection_cache_key.rb +16 -6
  35. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +41 -33
  36. data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
  37. data/lib/active_record/connection_adapters/abstract/query_cache.rb +37 -2
  38. data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -5
  39. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +11 -14
  40. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +68 -56
  41. data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -12
  42. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -60
  43. data/lib/active_record/connection_adapters/column.rb +1 -1
  44. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  45. data/lib/active_record/connection_adapters/mysql/database_statements.rb +8 -25
  46. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  47. data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -6
  48. data/lib/active_record/connection_adapters/postgresql/column.rb +28 -1
  49. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
  50. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -2
  51. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  52. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  53. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +10 -0
  54. data/lib/active_record/connection_adapters/postgresql/quoting.rb +32 -3
  55. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +18 -8
  56. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
  57. data/lib/active_record/connection_adapters/postgresql_adapter.rb +25 -19
  58. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  59. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +4 -4
  60. data/lib/active_record/core.rb +6 -4
  61. data/lib/active_record/enum.rb +8 -5
  62. data/lib/active_record/explain.rb +20 -9
  63. data/lib/active_record/fixtures.rb +5 -5
  64. data/lib/active_record/gem_version.rb +2 -2
  65. data/lib/active_record/integration.rb +13 -10
  66. data/lib/active_record/log_subscriber.rb +19 -17
  67. data/lib/active_record/migration.rb +35 -14
  68. data/lib/active_record/model_schema.rb +161 -52
  69. data/lib/active_record/no_touching.rb +4 -0
  70. data/lib/active_record/persistence.rb +41 -20
  71. data/lib/active_record/query_cache.rb +15 -17
  72. data/lib/active_record/querying.rb +3 -3
  73. data/lib/active_record/railties/controller_runtime.rb +1 -1
  74. data/lib/active_record/railties/databases.rake +9 -21
  75. data/lib/active_record/reflection.rb +20 -0
  76. data/lib/active_record/relation/batches.rb +10 -10
  77. data/lib/active_record/relation/calculations.rb +16 -12
  78. data/lib/active_record/relation/delegation.rb +2 -1
  79. data/lib/active_record/relation/finder_methods.rb +13 -11
  80. data/lib/active_record/relation/query_methods.rb +3 -3
  81. data/lib/active_record/relation.rb +12 -5
  82. data/lib/active_record/result.rb +7 -1
  83. data/lib/active_record/sanitization.rb +11 -1
  84. data/lib/active_record/schema_dumper.rb +10 -17
  85. data/lib/active_record/scoping/default.rb +5 -1
  86. data/lib/active_record/scoping/named.rb +18 -6
  87. data/lib/active_record/scoping.rb +4 -3
  88. data/lib/active_record/serialization.rb +1 -1
  89. data/lib/active_record/statement_cache.rb +2 -2
  90. data/lib/active_record/table_metadata.rb +4 -3
  91. data/lib/active_record/tasks/database_tasks.rb +14 -11
  92. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  93. data/lib/active_record/touch_later.rb +6 -1
  94. data/lib/active_record/transactions.rb +1 -1
  95. data/lib/active_record/type/internal/abstract_json.rb +5 -1
  96. data/lib/active_record/validations/uniqueness.rb +3 -4
  97. data/lib/active_record.rb +3 -2
  98. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  99. data/lib/rails/generators/active_record/migration.rb +8 -0
  100. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  101. metadata +7 -8
@@ -30,11 +30,11 @@ module ActiveRecord
30
30
  # end
31
31
  #
32
32
  # ==== Options
33
- # * <tt>:batch_size</tt> - Specifies the size of the batch. Default to 1000.
33
+ # * <tt>:batch_size</tt> - Specifies the size of the batch. Defaults to 1000.
34
34
  # * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
35
35
  # * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
36
36
  # * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
37
- # the order and limit have to be ignored due to batching.
37
+ # the order and limit have to be ignored due to batching.
38
38
  #
39
39
  # This is especially useful if you want multiple workers dealing with
40
40
  # the same processing queue. You can make worker 1 handle all the records
@@ -85,11 +85,11 @@ module ActiveRecord
85
85
  # To be yielded each record one by one, use #find_each instead.
86
86
  #
87
87
  # ==== Options
88
- # * <tt>:batch_size</tt> - Specifies the size of the batch. Default to 1000.
88
+ # * <tt>:batch_size</tt> - Specifies the size of the batch. Defaults to 1000.
89
89
  # * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
90
90
  # * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
91
91
  # * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
92
- # the order and limit have to be ignored due to batching.
92
+ # the order and limit have to be ignored due to batching.
93
93
  #
94
94
  # This is especially useful if you want multiple workers dealing with
95
95
  # the same processing queue. You can make worker 1 handle all the records
@@ -132,9 +132,9 @@ module ActiveRecord
132
132
  # If you do not provide a block to #in_batches, it will return a
133
133
  # BatchEnumerator which is enumerable.
134
134
  #
135
- # Person.in_batches.with_index do |relation, batch_index|
135
+ # Person.in_batches.each_with_index do |relation, batch_index|
136
136
  # puts "Processing relation ##{batch_index}"
137
- # relation.each { |relation| relation.delete_all }
137
+ # relation.delete_all
138
138
  # end
139
139
  #
140
140
  # Examples of calling methods on the returned BatchEnumerator object:
@@ -144,12 +144,12 @@ module ActiveRecord
144
144
  # Person.in_batches.each_record(&:party_all_night!)
145
145
  #
146
146
  # ==== Options
147
- # * <tt>:of</tt> - Specifies the size of the batch. Default to 1000.
148
- # * <tt>:load</tt> - Specifies if the relation should be loaded. Default to false.
147
+ # * <tt>:of</tt> - Specifies the size of the batch. Defaults to 1000.
148
+ # * <tt>:load</tt> - Specifies if the relation should be loaded. Defaults to false.
149
149
  # * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
150
150
  # * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
151
151
  # * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
152
- # the order and limit have to be ignored due to batching.
152
+ # the order and limit have to be ignored due to batching.
153
153
  #
154
154
  # This is especially useful if you want to work with the
155
155
  # ActiveRecord::Relation object instead of the array of records, or if
@@ -176,7 +176,7 @@ module ActiveRecord
176
176
  #
177
177
  # NOTE: It's not possible to set the order. That is automatically set to
178
178
  # ascending on the primary key ("id ASC") to make the batch ordering
179
- # consistent. Therefore the primary key must be orderable, e.g an integer
179
+ # consistent. Therefore the primary key must be orderable, e.g. an integer
180
180
  # or a string.
181
181
  #
182
182
  # NOTE: You can't set the limit either, that's used to control the batch
@@ -113,7 +113,10 @@ module ActiveRecord
113
113
  end
114
114
 
115
115
  if has_include?(column_name)
116
- construct_relation_for_association_calculations.calculate(operation, column_name)
116
+ relation = construct_relation_for_association_calculations
117
+ relation = relation.distinct if operation.to_s.downcase == "count"
118
+
119
+ relation.calculate(operation, column_name)
117
120
  else
118
121
  perform_calculation(operation, column_name)
119
122
  end
@@ -156,7 +159,7 @@ module ActiveRecord
156
159
  #
157
160
  def pluck(*column_names)
158
161
  if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
159
- return @records.pluck(*column_names)
162
+ return records.pluck(*column_names)
160
163
  end
161
164
 
162
165
  if has_include?(column_names.first)
@@ -194,11 +197,6 @@ module ActiveRecord
194
197
 
195
198
  if operation == "count"
196
199
  column_name ||= select_for_count
197
-
198
- unless arel.ast.grep(Arel::Nodes::OuterJoin).empty?
199
- distinct = true
200
- end
201
-
202
200
  column_name = primary_key if column_name == :all && distinct
203
201
  distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i
204
202
  end
@@ -240,6 +238,10 @@ module ActiveRecord
240
238
 
241
239
  select_value = operation_over_aggregate_column(column, operation, distinct)
242
240
 
241
+ if operation == "sum" && distinct
242
+ select_value.distinct = true
243
+ end
244
+
243
245
  column_alias = select_value.alias
244
246
  column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
245
247
  relation.select_values = [select_value]
@@ -284,7 +286,7 @@ module ActiveRecord
284
286
  operation,
285
287
  distinct).as(aggregate_alias)
286
288
  ]
287
- select_values += select_values unless having_clause.empty?
289
+ select_values += self.select_values unless having_clause.empty?
288
290
 
289
291
  select_values.concat group_columns.map { |aliaz, field|
290
292
  if field.respond_to?(:as)
@@ -308,8 +310,10 @@ module ActiveRecord
308
310
 
309
311
  Hash[calculated_data.map do |row|
310
312
  key = group_columns.map { |aliaz, col_name|
311
- column = calculated_data.column_types.fetch(aliaz) do
312
- type_for(col_name)
313
+ column = type_for(col_name) do
314
+ calculated_data.column_types.fetch(aliaz) do
315
+ Type::Value.new
316
+ end
313
317
  end
314
318
  type_cast_calculated_value(row[aliaz], column)
315
319
  }
@@ -342,9 +346,9 @@ module ActiveRecord
342
346
  @klass.connection.table_alias_for(table_name)
343
347
  end
344
348
 
345
- def type_for(field)
349
+ def type_for(field, &block)
346
350
  field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
347
- @klass.type_for_attribute(field_name)
351
+ @klass.type_for_attribute(field_name, &block)
348
352
  end
349
353
 
350
354
  def type_cast_calculated_value(value, type, operation = nil)
@@ -37,7 +37,8 @@ module ActiveRecord
37
37
 
38
38
  delegate :to_xml, :encode_with, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
39
39
  :[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
40
- :shuffle, :split, to: :records
40
+ :to_sentence, :to_formatted_s,
41
+ :shuffle, :split, :index, to: :records
41
42
 
42
43
  delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
43
44
  :connection, :columns_hash, :to => :klass
@@ -17,8 +17,8 @@ module ActiveRecord
17
17
  # Person.where("administrator = 1").order("created_on DESC").find(1)
18
18
  #
19
19
  # NOTE: The returned records may not be in the same order as the ids you
20
- # provide since database rows are unordered. You'd need to provide an explicit QueryMethods#order
21
- # option if you want the results are sorted.
20
+ # provide since database rows are unordered. You will need to provide an explicit QueryMethods#order
21
+ # option if you want the results to be sorted.
22
22
  #
23
23
  # ==== Find with lock
24
24
  #
@@ -343,18 +343,20 @@ module ActiveRecord
343
343
  # of results obtained should be provided in the +result_size+ argument and
344
344
  # the expected number of results should be provided in the +expected_size+
345
345
  # argument.
346
- def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc:
346
+ def raise_record_not_found_exception!(ids, result_size, expected_size, key = primary_key) #:nodoc:
347
347
  conditions = arel.where_sql(@klass.arel_engine)
348
348
  conditions = " [#{conditions}]" if conditions
349
+ name = @klass.name
349
350
 
350
351
  if Array(ids).size == 1
351
- error = "Couldn't find #{@klass.name} with '#{primary_key}'=#{ids}#{conditions}"
352
+ error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
353
+ raise RecordNotFound.new(error, name, key, ids)
352
354
  else
353
- error = "Couldn't find all #{@klass.name.pluralize} with '#{primary_key}': "
355
+ error = "Couldn't find all #{name.pluralize} with '#{key}': "
354
356
  error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
355
- end
356
357
 
357
- raise RecordNotFound, error
358
+ raise RecordNotFound, error
359
+ end
358
360
  end
359
361
 
360
362
  private
@@ -520,7 +522,7 @@ module ActiveRecord
520
522
 
521
523
  def find_take
522
524
  if loaded?
523
- @records.first
525
+ records.first
524
526
  else
525
527
  @take ||= limit(1).records.first
526
528
  end
@@ -537,7 +539,7 @@ module ActiveRecord
537
539
  MSG
538
540
  end
539
541
  if loaded?
540
- @records[index]
542
+ records[index]
541
543
  else
542
544
  offset ||= offset_index
543
545
  @offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
@@ -563,7 +565,7 @@ module ActiveRecord
563
565
 
564
566
  def find_nth_from_last(index)
565
567
  if loaded?
566
- @records[-index]
568
+ records[-index]
567
569
  else
568
570
  relation = if order_values.empty? && primary_key
569
571
  order(arel_attribute(primary_key).asc)
@@ -584,7 +586,7 @@ module ActiveRecord
584
586
 
585
587
  def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
586
588
  if loaded?
587
- @records[index, limit]
589
+ records[index, limit]
588
590
  else
589
591
  index += offset
590
592
  find_nth_with_limit(index, limit)
@@ -1141,9 +1141,9 @@ module ActiveRecord
1141
1141
  end
1142
1142
 
1143
1143
  def does_not_support_reverse?(order)
1144
- #uses sql function with multiple arguments
1145
- order =~ /\([^()]*,[^()]*\)/ ||
1146
- # uses "nulls first" like construction
1144
+ # Uses SQL function with multiple arguments.
1145
+ (order.include?(',') && order.split(',').find { |section| section.count('(') != section.count(')')}) ||
1146
+ # Uses "nulls first" like construction.
1147
1147
  order =~ /nulls (first|last)\Z/i
1148
1148
  end
1149
1149
 
@@ -347,7 +347,7 @@ module ActiveRecord
347
347
  # Please check unscoped if you want to remove all previous scopes (including
348
348
  # the default_scope) during the execution of a block.
349
349
  def scoping
350
- previous, klass.current_scope = klass.current_scope, self
350
+ previous, klass.current_scope = klass.current_scope(true), self
351
351
  yield
352
352
  ensure
353
353
  klass.current_scope = previous
@@ -372,6 +372,9 @@ module ActiveRecord
372
372
  #
373
373
  # # Update all books that match conditions, but limit it to 5 ordered by date
374
374
  # Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
375
+ #
376
+ # # Update all invoices and set the number column to its id value.
377
+ # Invoice.update_all('number = id')
375
378
  def update_all(updates)
376
379
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
377
380
 
@@ -576,8 +579,8 @@ module ActiveRecord
576
579
  # return value is the relation itself, not the records.
577
580
  #
578
581
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
579
- def load
580
- exec_queries unless loaded?
582
+ def load(&block)
583
+ exec_queries(&block) unless loaded?
581
584
 
582
585
  self
583
586
  end
@@ -686,6 +689,10 @@ module ActiveRecord
686
689
  "#<#{self.class.name} [#{entries.join(', ')}]>"
687
690
  end
688
691
 
692
+ def empty_scope? # :nodoc:
693
+ @values == klass.unscoped.values
694
+ end
695
+
689
696
  protected
690
697
 
691
698
  def load_records(records)
@@ -695,8 +702,8 @@ module ActiveRecord
695
702
 
696
703
  private
697
704
 
698
- def exec_queries
699
- @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze
705
+ def exec_queries(&block)
706
+ @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze
700
707
 
701
708
  preload = preload_values
702
709
  preload += includes_values unless eager_loading?
@@ -75,8 +75,14 @@ module ActiveRecord
75
75
  hash_rows[idx]
76
76
  end
77
77
 
78
+ def first
79
+ return nil if @rows.empty?
80
+ Hash[@columns.zip(@rows.first)]
81
+ end
82
+
78
83
  def last
79
- hash_rows.last
84
+ return nil if @rows.empty?
85
+ Hash[@columns.zip(@rows.last)]
80
86
  end
81
87
 
82
88
  def cast_values(type_overrides = {}) # :nodoc:
@@ -116,7 +116,17 @@ module ActiveRecord
116
116
  def sanitize_sql_hash_for_assignment(attrs, table)
117
117
  c = connection
118
118
  attrs.map do |attr, value|
119
- value = type_for_attribute(attr.to_s).serialize(value)
119
+ if value.is_a?(Base)
120
+ require "active_support/core_ext/string/filters"
121
+ ActiveSupport::Deprecation.warn(<<-WARNING.squish)
122
+ Passing `ActiveRecord::Base` objects to
123
+ `sanitize_sql_hash_for_assignment` (or methods which call it,
124
+ such as `update_all`) is deprecated. Please pass the id directly,
125
+ instead.
126
+ WARNING
127
+ else
128
+ value = type_for_attribute(attr.to_s).serialize(value)
129
+ end
120
130
  "#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
121
131
  end.join(', ')
122
132
  end
@@ -105,12 +105,7 @@ HEADER
105
105
  tbl = StringIO.new
106
106
 
107
107
  # first dump primary key column
108
- if @connection.respond_to?(:primary_keys)
109
- pk = @connection.primary_keys(table)
110
- pk = pk.first unless pk.size > 1
111
- else
112
- pk = @connection.primary_key(table)
113
- end
108
+ pk = @connection.primary_key(table)
114
109
 
115
110
  tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}"
116
111
 
@@ -132,10 +127,8 @@ HEADER
132
127
  tbl.print ", force: :cascade"
133
128
 
134
129
  table_options = @connection.table_options(table)
135
- tbl.print ", options: #{table_options.inspect}" unless table_options.blank?
136
-
137
- if comment = @connection.table_comment(table).presence
138
- tbl.print ", comment: #{comment.inspect}"
130
+ if table_options.present?
131
+ tbl.print ", #{format_options(table_options)}"
139
132
  end
140
133
 
141
134
  tbl.puts " do |t|"
@@ -218,13 +211,9 @@ HEADER
218
211
  index.columns.inspect,
219
212
  "name: #{index.name.inspect}",
220
213
  ]
221
- index_parts << 'unique: true' if index.unique
222
-
223
- index_lengths = (index.lengths || []).compact
224
- index_parts << "length: #{Hash[index.columns.zip(index.lengths)].inspect}" if index_lengths.any?
225
-
226
- index_orders = index.orders || {}
227
- index_parts << "order: #{index.orders.inspect}" if index_orders.any?
214
+ index_parts << "unique: true" if index.unique
215
+ index_parts << "length: { #{format_options(index.lengths)} }" if index.lengths.present?
216
+ index_parts << "order: { #{format_options(index.orders)} }" if index.orders.present?
228
217
  index_parts << "where: #{index.where.inspect}" if index.where
229
218
  index_parts << "using: #{index.using.inspect}" if index.using
230
219
  index_parts << "type: #{index.type.inspect}" if index.type
@@ -262,6 +251,10 @@ HEADER
262
251
  end
263
252
  end
264
253
 
254
+ def format_options(options)
255
+ options.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
256
+ end
257
+
265
258
  def remove_prefix_and_suffix(table)
266
259
  table.gsub(/^(#{@options[:table_name_prefix]})(.+)(#{@options[:table_name_suffix]})$/, "\\2")
267
260
  end
@@ -110,7 +110,11 @@ module ActiveRecord
110
110
 
111
111
  if self.default_scope_override
112
112
  # The user has defined their own default scope method, so call that
113
- evaluate_default_scope { default_scope }
113
+ evaluate_default_scope do
114
+ if scope = default_scope
115
+ (base_rel ||= relation).merge(scope)
116
+ end
117
+ end
114
118
  elsif default_scopes.any?
115
119
  base_rel ||= relation
116
120
  evaluate_default_scope do
@@ -29,13 +29,25 @@ module ActiveRecord
29
29
  end
30
30
  end
31
31
 
32
- def default_scoped # :nodoc:
33
- scope = build_default_scope
32
+ def scope_for_association(scope = relation) # :nodoc:
33
+ current_scope = self.current_scope
34
34
 
35
- if scope
36
- relation.spawn.merge!(scope)
35
+ if current_scope && current_scope.empty_scope?
36
+ scope
37
37
  else
38
- relation
38
+ default_scoped(scope)
39
+ end
40
+ end
41
+
42
+ def default_scoped(scope = relation) # :nodoc:
43
+ build_default_scope(scope) || scope
44
+ end
45
+
46
+ def default_extensions # :nodoc:
47
+ if scope = current_scope || build_default_scope
48
+ scope.extensions
49
+ else
50
+ []
39
51
  end
40
52
  end
41
53
 
@@ -174,7 +186,7 @@ module ActiveRecord
174
186
  protected
175
187
 
176
188
  def valid_scope_name?(name)
177
- if respond_to?(name, true)
189
+ if respond_to?(name, true) && logger
178
190
  logger.warn "Creating scope :#{name}. " \
179
191
  "Overwriting existing method #{self.name}.#{name}."
180
192
  end
@@ -10,8 +10,8 @@ module ActiveRecord
10
10
  end
11
11
 
12
12
  module ClassMethods
13
- def current_scope #:nodoc:
14
- ScopeRegistry.value_for(:current_scope, self)
13
+ def current_scope(skip_inherited_scope = false) # :nodoc:
14
+ ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
15
15
  end
16
16
 
17
17
  def current_scope=(scope) #:nodoc:
@@ -75,8 +75,9 @@ module ActiveRecord
75
75
  end
76
76
 
77
77
  # Obtains the value for a given +scope_type+ and +model+.
78
- def value_for(scope_type, model)
78
+ def value_for(scope_type, model, skip_inherited_scope = false)
79
79
  raise_invalid_scope_type!(scope_type)
80
+ return @registry[scope_type][model.name] if skip_inherited_scope
80
81
  klass = model
81
82
  base = model.base_class
82
83
  while klass <= base
@@ -9,7 +9,7 @@ module ActiveRecord #:nodoc:
9
9
  end
10
10
 
11
11
  def serializable_hash(options = nil)
12
- options = options.try(:clone) || {}
12
+ options = options.try(:dup) || {}
13
13
 
14
14
  options[:except] = Array(options[:except]).map(&:to_s)
15
15
  options[:except] |= Array(self.class.inheritance_column)
@@ -101,12 +101,12 @@ module ActiveRecord
101
101
  @bind_map = bind_map
102
102
  end
103
103
 
104
- def execute(params, klass, connection)
104
+ def execute(params, klass, connection, &block)
105
105
  bind_values = bind_map.bind params
106
106
 
107
107
  sql = query_builder.sql_for bind_values, connection
108
108
 
109
- klass.find_by_sql(sql, bind_values, preparable: true)
109
+ klass.find_by_sql(sql, bind_values, preparable: true, &block)
110
110
  end
111
111
  alias :call :execute
112
112
  end
@@ -42,10 +42,11 @@ module ActiveRecord
42
42
  end
43
43
 
44
44
  def associated_table(table_name)
45
- return self if table_name == arel_table.name
45
+ association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.to_s.singularize)
46
46
 
47
- association = klass._reflect_on_association(table_name)
48
- if association && !association.polymorphic?
47
+ if !association && table_name == arel_table.name
48
+ return self
49
+ elsif association && !association.polymorphic?
49
50
  association_klass = association.klass
50
51
  arel_table = association_klass.arel_table.alias(table_name)
51
52
  else
@@ -154,6 +154,8 @@ module ActiveRecord
154
154
  end
155
155
 
156
156
  def migrate
157
+ raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
158
+
157
159
  verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
158
160
  version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
159
161
  scope = ENV['SCOPE']
@@ -213,22 +215,22 @@ module ActiveRecord
213
215
  class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
214
216
  end
215
217
 
216
- def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
218
+ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env) # :nodoc:
217
219
  file ||= schema_file(format)
218
220
 
221
+ check_schema_file(file)
222
+ ActiveRecord::Base.establish_connection(configuration)
223
+
219
224
  case format
220
225
  when :ruby
221
- check_schema_file(file)
222
- ActiveRecord::Base.establish_connection(configuration)
223
226
  load(file)
224
227
  when :sql
225
- check_schema_file(file)
226
228
  structure_load(configuration, file)
227
229
  else
228
230
  raise ArgumentError, "unknown format #{format.inspect}"
229
231
  end
230
232
  ActiveRecord::InternalMetadata.create_table
231
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
233
+ ActiveRecord::InternalMetadata[:environment] = environment
232
234
  end
233
235
 
234
236
  def load_schema_for(*args)
@@ -249,8 +251,8 @@ module ActiveRecord
249
251
  end
250
252
 
251
253
  def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
252
- each_current_configuration(environment) { |configuration|
253
- load_schema configuration, format, file
254
+ each_current_configuration(environment) { |configuration, configuration_environment|
255
+ load_schema configuration, format, file, configuration_environment
254
256
  }
255
257
  ActiveRecord::Base.establish_connection(environment.to_sym)
256
258
  end
@@ -258,7 +260,7 @@ module ActiveRecord
258
260
  def check_schema_file(filename)
259
261
  unless File.exist?(filename)
260
262
  message = %{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}
261
- message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails)
263
+ message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails.root)
262
264
  Kernel.abort message
263
265
  end
264
266
  end
@@ -287,9 +289,10 @@ module ActiveRecord
287
289
  environments = [environment]
288
290
  environments << 'test' if environment == 'development'
289
291
 
290
- configurations = ActiveRecord::Base.configurations.values_at(*environments)
291
- configurations.compact.each do |configuration|
292
- yield configuration unless configuration['database'].blank?
292
+ ActiveRecord::Base.configurations.slice(*environments).each do |configuration_environment, configuration|
293
+ next unless configuration["database"]
294
+
295
+ yield configuration, configuration_environment
293
296
  end
294
297
  end
295
298
 
@@ -16,7 +16,7 @@ module ActiveRecord
16
16
  configuration.merge('encoding' => encoding)
17
17
  establish_connection configuration
18
18
  rescue ActiveRecord::StatementInvalid => error
19
- if /database .* already exists/ === error.message
19
+ if error.cause.is_a?(PG::DuplicateDatabase)
20
20
  raise DatabaseAlreadyExists
21
21
  else
22
22
  raise
@@ -8,7 +8,12 @@ module ActiveRecord
8
8
  end
9
9
 
10
10
  def touch_later(*names) # :nodoc:
11
- raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
11
+ unless persisted?
12
+ raise ActiveRecordError, <<-MSG.squish
13
+ cannot touch on a new or destroyed record object. Consider using
14
+ persisted?, new_record?, or destroyed? before touching
15
+ MSG
16
+ end
12
17
 
13
18
  @_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
14
19
  @_defer_touch_attrs |= names
@@ -124,7 +124,7 @@ module ActiveRecord
124
124
  # # statement will cause a PostgreSQL error, even though the unique
125
125
  # # constraint is no longer violated:
126
126
  # Number.create(i: 1)
127
- # # => "PGError: ERROR: current transaction is aborted, commands
127
+ # # => "PG::Error: ERROR: current transaction is aborted, commands
128
128
  # # ignored until end of transaction block"
129
129
  # end
130
130
  #
@@ -17,7 +17,11 @@ module ActiveRecord
17
17
  end
18
18
 
19
19
  def serialize(value)
20
- ::ActiveSupport::JSON.encode(value)
20
+ if value.nil?
21
+ nil
22
+ else
23
+ ::ActiveSupport::JSON.encode(value)
24
+ end
21
25
  end
22
26
 
23
27
  def accessor
@@ -86,11 +86,10 @@ module ActiveRecord
86
86
 
87
87
  def scope_relation(record, table, relation)
88
88
  Array(options[:scope]).each do |scope_item|
89
- if reflection = record.class._reflect_on_association(scope_item)
90
- scope_value = record.send(reflection.foreign_key)
91
- scope_item = reflection.foreign_key
89
+ scope_value = if record.class._reflect_on_association(scope_item)
90
+ record.association(scope_item).reader
92
91
  else
93
- scope_value = record._read_attribute(scope_item)
92
+ record._read_attribute(scope_item)
94
93
  end
95
94
  relation = relation.where(scope_item => scope_value)
96
95
  end