LoginSignup
8
8

More than 5 years have passed since last update.

railsモデルを削除して新しくmodelを追加したらIDが飛ばされることなく削除したモデルのIDが設定されてしまった。

Posted at

Category has_many goodsのような関連のデータでCategoryモデルを削除し、新規に作成した場合、削除したIDの次の数値がIDとなるのが期待される挙動です。(例 ID=23のモデルを削除したら次に作成されるモデルのIDは24)

しかし特定の状況下ではそうならずに削除したIDが新規に作成したモデルに割り振られる事があるようです。(例 ID=23のモデルを削除したら次に作成されるモデルのIDに23が割り振られる)

こうなると思わぬ関連付けされてしまうので困ります。

> Category.find(23).destroy
  Category Load (0.7ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 23 LIMIT 1
   (0.1ms)  BEGIN
  SQL (0.3ms)  DELETE FROM `categories` WHERE `categories`.`id` = 23

下に自分が起きたとき原因だろうと思われるところを上げてみます。

  1. railsはmysqlを使う際InnoDBをデフォルトで使う
    Ruby on Rails : migration 機能リファレンス

    なお、バックエンドデータベースとして MySQL を使用している場合、:options を指定しないと "ENGINE=InnoDB" がデフォルトで指定されます。

  2. mysqlのInnoDBは外部key制約で参照されているtableのデータを削除するときはTRUNCATEが使用される。
    12.2.9. TRUNCATE 構文

もしテーブルを参照する外部キー制約があれば、InnoDB テーブルに対しては、TRUNCATE TABLE が DELETE にマップされ、そうでなければ、高速切断(テーブルのドロップと再作成)が利用されます。外部キー制約の有無に関わらず、AUTO_INCREMENT カウンタが TRUNCATE TABLE によってリセットされます。

  1. テーブルでTRUNCATEを使用するとauto incrementがリセットされる。

メッチャ役に立つauto_incrementの話のスライド21~23ページ目を参考にした。

21. テーブルをTRUNCATEするとどうなる?(シーケンスが12まで振られてる状態で)TRUNCATE TABLE tbl;INSERT INTOtbl(user_name)VALUES(‘userXX’);
22. シーケンスが巻き戻った
23. DELETEでは巻き戻らないが、 TRUNCATEだと巻き戻る

上記の3つの条件が同時に起こっているとオートインクリメントの挙動が期待されていないものになるようです。

対策としてはrailsのhas_manyにはdependent オプションがあるのでそれを設定しとくべきだと思います。
設定すると親モデルを削除した際に子モデルも同時に削除されるというものです。

railsでhas_manyで関連したモデルのデータを一気に消すとき

8
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8