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
色々記事があるけど、公式ドキュメントが一番いい。