概要
ActiveRecord::Relation
の destroy_all
と delete_all
のメソッドの違いを検証
destroy_all
-
records
の要素1つ1つに対してdestroy
とreset
を実行 - レコード数の多い条件に対して実行する際は要注意
def destroy_all
records.each(&:destroy).tap { reset }
end
delete_all
- 直接SQLを実行し、対象のレコード全てに対して
DELETE
を実行する - レコード数が多い場合は
destroy_all
よりも早く実行できるが、destroy
は呼ばれないので、 削除時のバリデーションやcallback
等が呼ばれないことに要注意 -
INVALID_METHODS_FOR_DELETE_ALL
( =distinct
group
having
)等の集計関数を含んでいる場合はraise
される
def delete_all
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
value = get_value(method)
SINGLE_VALUE_METHODS.include?(method) ? value : value.any?
end
if invalid_methods.any?
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
end
if eager_loading?
relation = apply_join_dependency
return relation.delete_all
end
stmt = Arel::DeleteManager.new
stmt.from(table)
if has_join_values? || has_limit_or_offset?
@klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
else
stmt.wheres = arel.constraints
end
affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
reset
affected
end