destroy_allとdelete_all

More than 1 year has passed since last update.


概要

ActiveRecord::Relationdestroy_alldelete_all のメソッドの違いを検証


destroy_all



  • records の要素1つ1つに対して destroyreset を実行

  • レコード数の多い条件に対して実行する際は要注意

    def destroy_all

records.each(&:destroy).tap { reset }
end

https://github.com/rails/rails/blob/fe6adf43e124f4c9132e5a88a80ebba3f10fd2cb/activerecord/lib/active_record/relation.rb#L378


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

https://github.com/rails/rails/blob/fe6adf43e124f4c9132e5a88a80ebba3f10fd2cb/activerecord/lib/active_record/relation.rb#L400