Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
211
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

delete, delete_all, destroy, destroy_allについて

ActiveRecordでよく使う4つの削除系インスタンスメソッド、delete, delete_all, destroy, destroy_all。
個人的に毎回使い分けが混乱してしまうので、それぞれの動作をまとめました。

前提

  • Rails5系
  • Ruby-2.4

モデル関連は以下のような感じを想定してまとめます。(RailsGuides参照)

class Author < ApplicationRecord
  has_many :books, dependent: :destroy
end

class Book < ApplicationRecord
  belongs_to :author
end

destroy

削除を行う際に一番使うメソッド(だと思う)。
ActiveRecordを介して指定した条件のレコードを削除する。削除する際に、Modelにdependent: :destroyが設定されている関連がある場合、その関連も一緒に削除してくれる。

例えば、Author.find(1).destroyとすれば、一人のAuthorとそれに関連しているBook達を削除してくれる。
注意しないといけないのは、Modelに設定したdependent: :destroy。これがないと、Authorは削除されて、Booksだけが孤立してしまう状態になる。
稀にdependentを設定していないから、「あれ?関連付けが削除されない!!」ってあたふたするときが、個人的にあるw

補足

あと関連付け設定には、dependent: :destroyのほかに、dependent: :delete_allってのもある(has_one関連の場合はdependent: :delete)。
この場合、destroyを実行すると、ActiveRecordを介さないで直接SQLを実行して関連付けも削除します。

:destroyを設定した場合と:delete_allを設定した場合で、destroyを実行してログを見てみるとわかるが、前者はDELETEクエリが関連の数だけ実行されるが、後者だとDELETEクエリ1回だけ実行する。
つまり、後者の方が効率よく関連を削除できるというメリットがあるということ!

まだ自分はRails経験浅いのでわからないが、基本的なWebサービスとかでは:delete_allはあんまり使う機会無い気がする…。だいたいdependent: :destroyで事足りる気がする。

delete

指定した条件のレコードをSQLを直接実行して削除する。つまり、ActiveRecordを介さない。(「DELETEクエリを直接実行するのがdelete」という感じで覚えておけば、destroy、deleteどっちだっけ??ってことはなくなるかと。)

また関連付けられてるレコード削除しない。dependentが設定されていても関係なし。

個人的には、既にmodelでdependentで関連付けられてるけど、今回は関連付けは消したくない!って時に使う機会が多い気がする。

destroy_all

例えば、こんな感じ

Author.find(1).books.destroy_all

これで、一人のAuthorに関連しているbookがActiveRecordを介してすべて削除される(Authorを削除するわけじゃない)。

ちなみに、以下のようなモデル関連付けだったとすると、booksの関連付けのcategoriesもコールバックが呼び出されて削除される。

class Author < ApplicationRecord
  has_many :books, dependent: :destroy
end

class Book < ApplicationRecord
  belongs_to :author
  has_one :categories, dependent: :destroy
end

class Category < ApplicationRecord
  belongs_to :book
end  

delete_all

ここまで説明見ていただけたら察しがつくと思うが、

Author.find(1).books.delete_all

とすれば、一人のAuthorに関連付けられているbooksをすべてActiveRecordを介さないで削除してくれる。
この場合、deleteと同様にbooksの関連付けなどの設定は無視する(deleteコールバックが呼ばれない)。

つまり、まとめて複数のbooksデータを削除する場合に、効率よく削除ができるということ。
個人的にはあまり使う機会に出会ってないのだけど、deleteと同様で関連付けを無視してまとめて削除したい時に使うのが良いと思う。もしくは関連のみを削除する時とか?

ココまで踏まえて注意する所

  • 関連付けで削除するなら、modelにdependentの設定を忘れずに。
  • 関連付けも削除するdestroy,destroy_allか、関連を無視して削除するdelete, delete_allか、よく考えてコード書きましょう!

これ系の記事はググる一杯出るので、なんでわざわさまとめたかって言うと、以前仕事で退会処理みたいな処理を作ったのだが、has_manyで関連付けがあるオブジェクトをdelete_allで削除するようにしてたのだが、その関連付け先のオブジェクトが削除できておらず、DBに取り残されてしまう事案を起こしてしまった…。
その関連付けは把握してたのだが、delete_allとdestroy_allの違いを把握してなかったために起こしてしまったミスだった。

参考URL

色々記事があるけど、公式ドキュメントが一番いい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
211
Help us understand the problem. What are the problem?