activerecord 5.2.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.

Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +214 -0
  3. data/lib/active_record/association_relation.rb +3 -3
  4. data/lib/active_record/associations.rb +9 -9
  5. data/lib/active_record/associations/alias_tracker.rb +1 -1
  6. data/lib/active_record/associations/association.rb +25 -10
  7. data/lib/active_record/associations/belongs_to_association.rb +14 -5
  8. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
  9. data/lib/active_record/associations/builder/belongs_to.rb +11 -2
  10. data/lib/active_record/associations/collection_association.rb +19 -15
  11. data/lib/active_record/associations/collection_proxy.rb +8 -34
  12. data/lib/active_record/associations/has_many_association.rb +9 -0
  13. data/lib/active_record/associations/has_many_through_association.rb +25 -1
  14. data/lib/active_record/associations/has_one_association.rb +8 -0
  15. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  16. data/lib/active_record/associations/join_dependency.rb +39 -64
  17. data/lib/active_record/associations/join_dependency/join_association.rb +12 -18
  18. data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
  19. data/lib/active_record/associations/singular_association.rb +4 -10
  20. data/lib/active_record/associations/through_association.rb +1 -1
  21. data/lib/active_record/attribute_methods/dirty.rb +15 -10
  22. data/lib/active_record/attribute_methods/read.rb +1 -1
  23. data/lib/active_record/autosave_association.rb +7 -2
  24. data/lib/active_record/callbacks.rb +4 -0
  25. data/lib/active_record/collection_cache_key.rb +2 -2
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +14 -8
  27. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +19 -6
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +5 -14
  33. data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
  34. data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
  35. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -19
  36. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  37. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -2
  38. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
  39. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
  40. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
  41. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
  42. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  43. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -26
  44. data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
  45. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
  46. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -0
  47. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
  48. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -4
  49. data/lib/active_record/core.rb +2 -1
  50. data/lib/active_record/counter_cache.rb +17 -13
  51. data/lib/active_record/enum.rb +1 -0
  52. data/lib/active_record/errors.rb +18 -12
  53. data/lib/active_record/gem_version.rb +1 -1
  54. data/lib/active_record/log_subscriber.rb +1 -1
  55. data/lib/active_record/migration.rb +1 -1
  56. data/lib/active_record/migration/compatibility.rb +15 -15
  57. data/lib/active_record/model_schema.rb +1 -1
  58. data/lib/active_record/persistence.rb +6 -5
  59. data/lib/active_record/query_cache.rb +4 -11
  60. data/lib/active_record/querying.rb +1 -1
  61. data/lib/active_record/railtie.rb +1 -3
  62. data/lib/active_record/relation.rb +39 -20
  63. data/lib/active_record/relation/calculations.rb +11 -8
  64. data/lib/active_record/relation/delegation.rb +30 -0
  65. data/lib/active_record/relation/finder_methods.rb +10 -8
  66. data/lib/active_record/relation/merger.rb +10 -11
  67. data/lib/active_record/relation/predicate_builder.rb +20 -14
  68. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  69. data/lib/active_record/relation/query_attribute.rb +5 -3
  70. data/lib/active_record/relation/query_methods.rb +45 -19
  71. data/lib/active_record/relation/spawn_methods.rb +1 -1
  72. data/lib/active_record/scoping/named.rb +2 -0
  73. data/lib/active_record/tasks/database_tasks.rb +1 -1
  74. data/lib/active_record/timestamp.rb +8 -1
  75. data/lib/active_record/transactions.rb +23 -20
  76. data/lib/active_record/type/serialized.rb +4 -0
  77. metadata +9 -10
@@ -319,7 +319,7 @@ module ActiveRecord
319
319
 
320
320
  relation = construct_relation_for_exists(conditions)
321
321
 
322
- skip_query_cache_if_necessary { connection.select_value(relation.arel, "#{name} Exists") } ? true : false
322
+ skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists") } ? true : false
323
323
  rescue ::RangeError
324
324
  false
325
325
  end
@@ -359,11 +359,15 @@ module ActiveRecord
359
359
  end
360
360
 
361
361
  def construct_relation_for_exists(conditions)
362
- relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
362
+ if distinct_value && offset_value
363
+ relation = limit(1)
364
+ else
365
+ relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
366
+ end
363
367
 
364
368
  case conditions
365
369
  when Array, Hash
366
- relation.where!(conditions)
370
+ relation.where!(conditions) unless conditions.empty?
367
371
  else
368
372
  relation.where!(primary_key => conditions) unless conditions == :none
369
373
  end
@@ -373,13 +377,12 @@ module ActiveRecord
373
377
 
374
378
  def construct_join_dependency
375
379
  including = eager_load_values + includes_values
376
- joins = joins_values.select { |join| join.is_a?(Arel::Nodes::Join) }
377
380
  ActiveRecord::Associations::JoinDependency.new(
378
- klass, table, including, alias_tracker(joins)
381
+ klass, table, including
379
382
  )
380
383
  end
381
384
 
382
- def apply_join_dependency(eager_loading: true)
385
+ def apply_join_dependency(eager_loading: group_values.empty?)
383
386
  join_dependency = construct_join_dependency
384
387
  relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
385
388
 
@@ -392,7 +395,6 @@ module ActiveRecord
392
395
  end
393
396
 
394
397
  if block_given?
395
- relation._select!(join_dependency.aliases.columns)
396
398
  yield relation, join_dependency
397
399
  else
398
400
  relation
@@ -419,7 +421,7 @@ module ActiveRecord
419
421
  raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
420
422
 
421
423
  expects_array = ids.first.kind_of?(Array)
422
- return ids.first if expects_array && ids.first.empty?
424
+ return [] if expects_array && ids.first.empty?
423
425
 
424
426
  ids = ids.flatten.compact.uniq
425
427
 
@@ -117,13 +117,11 @@ module ActiveRecord
117
117
  if other.klass == relation.klass
118
118
  relation.joins!(*other.joins_values)
119
119
  else
120
- alias_tracker = nil
121
120
  joins_dependency = other.joins_values.map do |join|
122
121
  case join
123
122
  when Hash, Symbol, Array
124
- alias_tracker ||= other.alias_tracker
125
123
  ActiveRecord::Associations::JoinDependency.new(
126
- other.klass, other.table, join, alias_tracker
124
+ other.klass, other.table, join
127
125
  )
128
126
  else
129
127
  join
@@ -140,13 +138,11 @@ module ActiveRecord
140
138
  if other.klass == relation.klass
141
139
  relation.left_outer_joins!(*other.left_outer_joins_values)
142
140
  else
143
- alias_tracker = nil
144
141
  joins_dependency = other.left_outer_joins_values.map do |join|
145
142
  case join
146
143
  when Hash, Symbol, Array
147
- alias_tracker ||= other.alias_tracker
148
144
  ActiveRecord::Associations::JoinDependency.new(
149
- other.klass, other.table, join, alias_tracker
145
+ other.klass, other.table, join
150
146
  )
151
147
  else
152
148
  join
@@ -160,10 +156,10 @@ module ActiveRecord
160
156
  def merge_multi_values
161
157
  if other.reordering_value
162
158
  # override any order specified in the original relation
163
- relation.reorder! other.order_values
159
+ relation.reorder!(*other.order_values)
164
160
  elsif other.order_values.any?
165
161
  # merge in order_values from relation
166
- relation.order! other.order_values
162
+ relation.order!(*other.order_values)
167
163
  end
168
164
 
169
165
  extensions = other.extensions - relation.extensions
@@ -179,9 +175,7 @@ module ActiveRecord
179
175
  end
180
176
 
181
177
  def merge_clauses
182
- if relation.from_clause.empty? && !other.from_clause.empty?
183
- relation.from_clause = other.from_clause
184
- end
178
+ relation.from_clause = other.from_clause if replace_from_clause?
185
179
 
186
180
  where_clause = relation.where_clause.merge(other.where_clause)
187
181
  relation.where_clause = where_clause unless where_clause.empty?
@@ -189,6 +183,11 @@ module ActiveRecord
189
183
  having_clause = relation.having_clause.merge(other.having_clause)
190
184
  relation.having_clause = having_clause unless having_clause.empty?
191
185
  end
186
+
187
+ def replace_from_clause?
188
+ relation.from_clause.empty? && !other.from_clause.empty? &&
189
+ relation.klass.base_class == other.klass.base_class
190
+ end
192
191
  end
193
192
  end
194
193
  end
@@ -48,7 +48,12 @@ module ActiveRecord
48
48
  end
49
49
 
50
50
  def build(attribute, value)
51
- handler_for(value).call(attribute, value)
51
+ if table.type(attribute.name).force_equality?(value)
52
+ bind = build_bind_attribute(attribute.name, value)
53
+ attribute.eq(bind)
54
+ else
55
+ handler_for(value).call(attribute, value)
56
+ end
52
57
  end
53
58
 
54
59
  def build_bind_attribute(column_name, value)
@@ -88,20 +93,21 @@ module ActiveRecord
88
93
  queries.reduce(&:or)
89
94
  elsif table.aggregated_with?(key)
90
95
  mapping = table.reflect_on_aggregation(key).mapping
91
- queries = Array.wrap(value).map do |object|
92
- mapping.map do |field_attr, aggregate_attr|
93
- if mapping.size == 1 && !object.respond_to?(aggregate_attr)
94
- build(table.arel_attribute(field_attr), object)
95
- else
96
- build(table.arel_attribute(field_attr), object.send(aggregate_attr))
97
- end
98
- end.reduce(&:and)
96
+ values = value.nil? ? [nil] : Array.wrap(value)
97
+ if mapping.length == 1 || values.empty?
98
+ column_name, aggr_attr = mapping.first
99
+ values = values.map do |object|
100
+ object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object
101
+ end
102
+ build(table.arel_attribute(column_name), values)
103
+ else
104
+ queries = values.map do |object|
105
+ mapping.map do |field_attr, aggregate_attr|
106
+ build(table.arel_attribute(field_attr), object.try!(aggregate_attr))
107
+ end.reduce(&:and)
108
+ end
109
+ queries.reduce(&:or)
99
110
  end
100
- queries.reduce(&:or)
101
- # FIXME: Deprecate this and provide a public API to force equality
102
- elsif (value.is_a?(Range) || value.is_a?(Array)) &&
103
- table.type(key.to_s).respond_to?(:subtype)
104
- BasicObjectHandler.new(self).call(table.arel_attribute(key), value)
105
111
  else
106
112
  build(table.arel_attribute(key), value)
107
113
  end
@@ -19,10 +19,10 @@ module ActiveRecord
19
19
  when 0 then NullPredicate
20
20
  when 1 then predicate_builder.build(attribute, values.first)
21
21
  else
22
- bind_values = values.map do |v|
22
+ values.map! do |v|
23
23
  predicate_builder.build_bind_attribute(attribute.name, v)
24
24
  end
25
- attribute.in(bind_values)
25
+ values.empty? ? NullPredicate : attribute.in(values)
26
26
  end
27
27
 
28
28
  unless nils.empty?
@@ -18,13 +18,15 @@ module ActiveRecord
18
18
  end
19
19
 
20
20
  def nil?
21
- !value_before_type_cast.is_a?(StatementCache::Substitute) &&
22
- (value_before_type_cast.nil? || value_for_database.nil?)
21
+ unless value_before_type_cast.is_a?(StatementCache::Substitute)
22
+ value_before_type_cast.nil? ||
23
+ type.respond_to?(:subtype, true) && value_for_database.nil?
24
+ end
23
25
  end
24
26
 
25
27
  def boundable?
26
28
  return @_boundable if defined?(@_boundable)
27
- nil?
29
+ value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
28
30
  @_boundable = true
29
31
  rescue ::RangeError
30
32
  @_boundable = false
@@ -893,8 +893,8 @@ module ActiveRecord
893
893
  self
894
894
  end
895
895
 
896
- def skip_query_cache! # :nodoc:
897
- self.skip_query_cache_value = true
896
+ def skip_query_cache!(value = true) # :nodoc:
897
+ self.skip_query_cache_value = value
898
898
  self
899
899
  end
900
900
 
@@ -903,11 +903,12 @@ module ActiveRecord
903
903
  @arel ||= build_arel(aliases)
904
904
  end
905
905
 
906
+ # Returns a relation value with a given name
907
+ def get_value(name) # :nodoc:
908
+ @values.fetch(name, DEFAULT_VALUES[name])
909
+ end
910
+
906
911
  protected
907
- # Returns a relation value with a given name
908
- def get_value(name) # :nodoc:
909
- @values.fetch(name, DEFAULT_VALUES[name])
910
- end
911
912
 
912
913
  # Sets the relation value with the given name
913
914
  def set_value(name, value) # :nodoc:
@@ -1011,19 +1012,19 @@ module ActiveRecord
1011
1012
  def build_join_query(manager, buckets, join_type, aliases)
1012
1013
  buckets.default = []
1013
1014
 
1014
- association_joins = buckets[:association_join]
1015
- stashed_association_joins = buckets[:stashed_join]
1016
- join_nodes = buckets[:join_node].uniq
1017
- string_joins = buckets[:string_join].map(&:strip).uniq
1015
+ association_joins = buckets[:association_join]
1016
+ stashed_joins = buckets[:stashed_join]
1017
+ join_nodes = buckets[:join_node].uniq
1018
+ string_joins = buckets[:string_join].map(&:strip).uniq
1018
1019
 
1019
1020
  join_list = join_nodes + convert_join_strings_to_ast(string_joins)
1020
1021
  alias_tracker = alias_tracker(join_list, aliases)
1021
1022
 
1022
1023
  join_dependency = ActiveRecord::Associations::JoinDependency.new(
1023
- klass, table, association_joins, alias_tracker
1024
+ klass, table, association_joins
1024
1025
  )
1025
1026
 
1026
- joins = join_dependency.join_constraints(stashed_association_joins, join_type)
1027
+ joins = join_dependency.join_constraints(stashed_joins, join_type, alias_tracker)
1027
1028
  joins.each { |join| manager.from(join) }
1028
1029
 
1029
1030
  manager.join_sources.concat(join_list)
@@ -1049,17 +1050,36 @@ module ActiveRecord
1049
1050
  end
1050
1051
 
1051
1052
  def arel_columns(columns)
1052
- columns.map do |field|
1053
- if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
1054
- arel_attribute(field)
1055
- elsif Symbol === field
1056
- connection.quote_table_name(field.to_s)
1053
+ columns.flat_map do |field|
1054
+ case field
1055
+ when Symbol
1056
+ field = field.to_s
1057
+ arel_column(field) { connection.quote_table_name(field) }
1058
+ when String
1059
+ arel_column(field) { field }
1060
+ when Proc
1061
+ field.call
1057
1062
  else
1058
1063
  field
1059
1064
  end
1060
1065
  end
1061
1066
  end
1062
1067
 
1068
+ def arel_column(field)
1069
+ field = klass.attribute_alias(field) if klass.attribute_alias?(field)
1070
+ from = from_clause.name || from_clause.value
1071
+
1072
+ if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
1073
+ arel_attribute(field)
1074
+ else
1075
+ yield
1076
+ end
1077
+ end
1078
+
1079
+ def table_name_matches?(from)
1080
+ /(?:\A|(?<!FROM)\s)(?:\b#{table.name}\b|#{connection.quote_table_name(table.name)})(?!\.)/i.match?(from.to_s)
1081
+ end
1082
+
1063
1083
  def reverse_sql_order(order_query)
1064
1084
  if order_query.empty?
1065
1085
  return [arel_attribute(primary_key).desc] if primary_key
@@ -1141,14 +1161,20 @@ module ActiveRecord
1141
1161
  order_args.map! do |arg|
1142
1162
  case arg
1143
1163
  when Symbol
1144
- arel_attribute(arg).asc
1164
+ arg = arg.to_s
1165
+ arel_column(arg) {
1166
+ Arel.sql(connection.quote_table_name(arg))
1167
+ }.asc
1145
1168
  when Hash
1146
1169
  arg.map { |field, dir|
1147
1170
  case field
1148
1171
  when Arel::Nodes::SqlLiteral
1149
1172
  field.send(dir.downcase)
1150
1173
  else
1151
- arel_attribute(field).send(dir.downcase)
1174
+ field = field.to_s
1175
+ arel_column(field) {
1176
+ Arel.sql(connection.quote_table_name(field))
1177
+ }.send(dir.downcase)
1152
1178
  end
1153
1179
  }
1154
1180
  else
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  module SpawnMethods
9
9
  # This is overridden by Associations::CollectionProxy
10
10
  def spawn #:nodoc:
11
- clone
11
+ @delegate_to_klass ? klass.all : clone
12
12
  end
13
13
 
14
14
  # Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
@@ -195,6 +195,8 @@ module ActiveRecord
195
195
  scope
196
196
  end
197
197
  end
198
+
199
+ generate_relation_method(name)
198
200
  end
199
201
 
200
202
  private
@@ -122,7 +122,7 @@ module ActiveRecord
122
122
  $stderr.puts "Database '#{configuration['database']}' already exists"
123
123
  rescue Exception => error
124
124
  $stderr.puts error
125
- $stderr.puts "Couldn't create database for #{configuration.inspect}"
125
+ $stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
126
126
  raise
127
127
  end
128
128
 
@@ -52,7 +52,14 @@ module ActiveRecord
52
52
  clear_timestamp_attributes
53
53
  end
54
54
 
55
- class_methods do
55
+ module ClassMethods # :nodoc:
56
+ def touch_attributes_with_time(*names, time: nil)
57
+ attribute_names = timestamp_attributes_for_update_in_model
58
+ attribute_names |= names.map(&:to_s)
59
+ time ||= current_time_from_proper_timezone
60
+ attribute_names.each_with_object({}) { |attr_name, result| result[attr_name] = time }
61
+ end
62
+
56
63
  private
57
64
  def timestamp_attributes_for_create_in_model
58
65
  timestamp_attributes_for_create.select { |c| column_names.include?(c) }
@@ -340,11 +340,13 @@ module ActiveRecord
340
340
  # Ensure that it is not called if the object was never persisted (failed create),
341
341
  # but call it after the commit of a destroyed object.
342
342
  def committed!(should_run_callbacks: true) #:nodoc:
343
- if should_run_callbacks && destroyed? || persisted?
343
+ if should_run_callbacks && (destroyed? || persisted?)
344
+ @_committed_already_called = true
344
345
  _run_commit_without_transaction_enrollment_callbacks
345
346
  _run_commit_callbacks
346
347
  end
347
348
  ensure
349
+ @_committed_already_called = false
348
350
  force_clear_transaction_record_state
349
351
  end
350
352
 
@@ -382,13 +384,7 @@ module ActiveRecord
382
384
  status = nil
383
385
  self.class.transaction do
384
386
  add_to_transaction
385
- begin
386
- status = yield
387
- rescue ActiveRecord::Rollback
388
- clear_transaction_record_state
389
- status = nil
390
- end
391
-
387
+ status = yield
392
388
  raise ActiveRecord::Rollback unless status
393
389
  end
394
390
  status
@@ -398,17 +394,29 @@ module ActiveRecord
398
394
  end
399
395
  end
400
396
 
397
+ protected
398
+ attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
399
+
401
400
  private
402
401
 
403
402
  # Save the new record state and id of a record so it can be restored later if a transaction fails.
404
403
  def remember_transaction_record_state
405
- @_start_transaction_state[:id] = id
406
404
  @_start_transaction_state.reverse_merge!(
405
+ id: id,
407
406
  new_record: @new_record,
408
407
  destroyed: @destroyed,
409
408
  frozen?: frozen?,
410
409
  )
411
410
  @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
411
+ remember_new_record_before_last_commit
412
+ end
413
+
414
+ def remember_new_record_before_last_commit
415
+ if _committed_already_called
416
+ @_new_record_before_last_commit = false
417
+ else
418
+ @_new_record_before_last_commit = @_start_transaction_state[:new_record]
419
+ end
412
420
  end
413
421
 
414
422
  # Clear the new record state and id of a record.
@@ -440,22 +448,16 @@ module ActiveRecord
440
448
  end
441
449
  end
442
450
 
443
- # Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
444
- def transaction_record_state(state)
445
- @_start_transaction_state[state]
446
- end
447
-
448
451
  # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
449
452
  def transaction_include_any_action?(actions)
450
453
  actions.any? do |action|
451
454
  case action
452
455
  when :create
453
- transaction_record_state(:new_record)
454
- when :destroy
455
- defined?(@_trigger_destroy_callback) && @_trigger_destroy_callback
456
+ persisted? && @_new_record_before_last_commit
456
457
  when :update
457
- !(transaction_record_state(:new_record) || destroyed?) &&
458
- (defined?(@_trigger_update_callback) && @_trigger_update_callback)
458
+ !(@_new_record_before_last_commit || destroyed?) && _trigger_update_callback
459
+ when :destroy
460
+ _trigger_destroy_callback
459
461
  end
460
462
  end
461
463
  end
@@ -491,7 +493,8 @@ module ActiveRecord
491
493
 
492
494
  def update_attributes_from_transaction_state(transaction_state)
493
495
  if transaction_state && transaction_state.finalized?
494
- restore_transaction_record_state if transaction_state.rolledback?
496
+ restore_transaction_record_state(transaction_state.fully_rolledback?) if transaction_state.rolledback?
497
+ force_clear_transaction_record_state if transaction_state.fully_committed?
495
498
  clear_transaction_record_state if transaction_state.fully_completed?
496
499
  end
497
500
  end