ORM

モデルのデータをまとめて削除する

app/controllers/test_controller.rb
class TestController < ApplicationController
  def index
    Employee.where('id <= 10').delete_all
    @test = Employee.count
  end
end

説明

\n

1delete_allメソッドの基本

\n

モデルのデータをまとめて削除するには、delete_allメソッドを使用します:

\n \n
\n
モデル.delete_all
\n
\n \n

このメソッドを実行すると、該当するモデルのすべてのレコードが一度に削除されます。

\n \n
\n
Employee.delete_all  # Employeeテーブルの全レコードを削除
\n
\n\n\n\n

2条件付きデータ削除

\n

特定の条件に一致するデータだけを削除したい場合は、whereメソッドと組み合わせて使用します:

\n \n
\n
Employee.where("id <= ?", 20).delete_all
\n
\n \n

上の例では、Employeeモデルのidが20以下のデータを削除しています。

\n \n

他の条件指定の例:

\n \n
\n
# 退職済みの従業員を削除\nEmployee.where(status: "退職").delete_all\n\n# 特定の部署の従業員を削除\nEmployee.where(department: "営業部").delete_all\n\n# 1年以上更新されていないレコードを削除\nEmployee.where("updated_at < ?", 1.year.ago).delete_all
\n
\n\n\n\n

3delete_allとdestroy_allの違い

\n

Railsには似たような機能を持つdestroy_allメソッドもありますが、重要な違いがあります:

\n \n
ポイント
\n

delete_all:

\n
    \n
  • SQLのDELETE文を直接実行するため高速
  • \n
  • モデルのコールバックは実行されない
  • \n
  • 関連するレコードは自動削除されない(dependent: :destroyは無視される)
  • \n
\n \n

destroy_all:

\n
    \n
  • 各レコードに対してdestroyメソッドを呼び出すため遅い
  • \n
  • モデルのコールバックが実行される
  • \n
  • 関連するレコードも適切に処理される(dependent: :destroyが機能する)
  • \n
\n
\n \n

適切なメソッドの選択:

\n
    \n
  • 単純にデータを削除するだけならdelete_allが高速
  • \n
  • 関連するレコードも削除したい場合や、コールバックが必要な場合はdestroy_allを使用
  • \n
\n\n\n\n

4delete_allの戻り値

\n

delete_allメソッドは、削除されたレコードの数を整数で返します:

\n \n
\n
deleted_count = Employee.where(department: "営業部").delete_all\nputs "#{deleted_count}件のレコードが削除されました"
\n
\n \n

この戻り値を使用して、削除処理の結果をユーザーに通知したり、ログに記録したりすることができます。

\n\n\n\n

5実践的な使用例

\n

コントローラーでの実際の使用例:

\n \n
\n
class EmployeesController < ApplicationController\n  def bulk_delete\n    if params[:department].present?\n      # 特定の部署の従業員を削除\n      count = Employee.where(department: params[:department]).delete_all\n      flash[:notice] = "#{count}人の#{params[:department]}の従業員を削除しました"\n    elsif params[:before_date].present?\n      # 特定の日付より前に登録された従業員を削除\n      date = Date.parse(params[:before_date])\n      count = Employee.where("created_at < ?", date).delete_all\n      flash[:notice] = "#{date.strftime('%Y年%m月%d日')}より前に登録された#{count}人の従業員を削除しました"\n    else\n      flash[:alert] = "削除条件が指定されていません"\n    end\n    \n    redirect_to employees_path\n  end\n  \n  def clear_inactive\n    # 90日以上ログインしていないユーザーを削除\n    count = Employee.where("last_login_at < ?", 90.days.ago).delete_all\n    \n    respond_to do |format|\n      format.html {\n        flash[:notice] = "#{count}人の非アクティブユーザーを削除しました"\n        redirect_to admin_dashboard_path\n      }\n      format.json {\n        render json: { deleted_count: count, status: "success" }\n      }\n    end\n  end\nend
\n
\n\n\n
ポイント
\n

注意事項:

\n
    \n
  • delete_allは元に戻せない操作なので、実行前にバックアップを取ることをお勧めします。
  • \n
  • 本番環境で大量のデータを削除する場合は、データベースのパフォーマンスに影響する可能性があるため、オフピーク時に実行することを検討してください。
  • \n
  • 関連データの整合性を保つため、外部キー制約がある場合は特に注意が必要です。
  • \n
  • 大規模なデータ削除はトランザクション内で行うとより安全です。
  • \n
\n