subtitle

RaiseTechの各種コースをはじめとしたイロイロな学習の記録

テーブルのレコードを削除するときの注意点

現時点でのテーブル状態は、下記の通り。

※テーブルの構成は「Railsのデータベース(SQLite)の中身を直接扱う」参照。

sqlite> select * from users;
1|a@a|$2a$12$zF.GB3qpVi51u1JFFZpby.gRSlyaoMw08yJ3Id5.h.TYkXPmSLiLm||||2021-02-07 04:40:45.542872|2021-02-07 04:47:30.286894
3|c@example.com|$2a$12$kpls5Ks4AIUoaR5MsWpsienZCFp7lJw3N39TNU7aUVkY61eTPBFBW||||2021-02-07 05:28:05.516165|2021-02-07 05:46:04.506077
4|b@b|$2a$12$ZHykJ9M0KmnKEygZpatg3esU1ZyInpOSZZ8i60pJGkyyVJm0/WF2S||||2021-02-07 13:50:32.304258|2021-02-07 13:50:32.304258

qlite> select * from tweets;
2|一つ目|1|2021-02-07 13:31:53.860680|2021-02-07 13:31:53.860680
3|一つ目|1|2021-02-07 13:33:28.845603|2021-02-07 13:33:28.845603
4|2つ目|1|2021-02-07 13:34:37.795933|2021-02-07 13:34:37.795933
5|3つ目|1|2021-02-07 13:34:49.656390|2021-02-07 13:34:49.656390
6|Cの投稿1つ目|3|2021-02-07 13:35:46.003803|2021-02-07 13:35:46.003803
7|ネコカワイイ!!(*'ω'*)|1|2021-02-09 15:17:09.475970|2021-02-09 15:17:09.475970
8|お風呂のドアの外で待っているところがカワイイ!|1|2021-02-09 15:18:01.856668|2021-02-09 15:18:01.856668
9|お皿を洗っていると、足にお尻を乗せてくる|4|2021-02-09 15:19:28.878144|2021-02-09 15:19:28.878144
10|ネコ、昨日の水絶対飲まない(賢い!)|4|2021-02-09 15:27:50.930072|2021-02-09 15:27:50.930072
11|そこにいるだけでカワイイ!|4|2021-02-09 15:29:08.067910|2021-02-09 15:29:08.067910


アカウントを削除する。

c@example.com(user_id=3)


シモベNo.3が消えている。

シモベNo.3のツイートは、「Cの投稿1つ目」という文字列である。

ユーザーは消しても、ツイートは残っている。


sqlite> select * from users;
1|a@a|$2a$12$zF.GB3qpVi51u1JFFZpby.gRSlyaoMw08yJ3Id5.h.TYkXPmSLiLm||||2021-02-07 04:40:45.542872|2021-02-07 04:47:30.286894
4|b@b|$2a$12$ZHykJ9M0KmnKEygZpatg3esU1ZyInpOSZZ8i60pJGkyyVJm0/WF2S||||2021-02-07 13:50:32.304258|2021-02-07 13:50:32.304258

sqlite> select * from tweets;
2|一つ目|1|2021-02-07 13:31:53.860680|2021-02-07 13:31:53.860680
3|一つ目|1|2021-02-07 13:33:28.845603|2021-02-07 13:33:28.845603
4|2つ目|1|2021-02-07 13:34:37.795933|2021-02-07 13:34:37.795933
5|3つ目|1|2021-02-07 13:34:49.656390|2021-02-07 13:34:49.656390
6|Cの投稿1つ目|3|2021-02-07 13:35:46.003803|2021-02-07 13:35:46.003803
7|ネコカワイイ!!(*'ω'*)|1|2021-02-09 15:17:09.475970|2021-02-09 15:17:09.475970
8|お風呂のドアの外で待っているところがカワイイ!|1|2021-02-09 15:18:01.856668|2021-02-09 15:18:01.856668
9|お皿を洗っていると、足にお尻を乗せてくる|4|2021-02-09 15:19:28.878144|2021-02-09 15:19:28.878144
10|ネコ、昨日の水絶対飲まない(賢い!)|4|2021-02-09 15:27:50.930072|2021-02-09 15:27:50.930072
11|そこにいるだけでカワイイ!|4|2021-02-09 15:29:08.067910|2021-02-09 15:29:08.067910


tweetsテーブルには、先ほど削除したユーザー(user_id = 3)がつぶやいた内容が、ユーザー情報とともに残っているので、下記のSQL文では、すでに消去されているユーザーのIDを返す。

sqlite> select user_id from tweets where id = 6;
3


これは、テーブルに残っている情報を抽出しているだけなので、特に問題ないが、このuser_idを使って、usersテーブルにレコードされているemailを抽出しようとすると、データがないので当然ながら何も抽出できない。

sqlite> select email from users where id = (select user_id from tweets where id = 10); 
b@b     # 10番目のツイートはシモベNo.4が書いたので、emailが返ってくる
sqlite> select email from users where id = (select user_id from tweets where id = 6);   
sqlite> # 6番目のツイートは先ほど削除したシモベNo.3が書いたので、usersレコードから消えていてemailが返ってこない


こういうことを考慮しないと、アプリ作成時に思わぬところでバグになる。

usersテーブルのレコードが削除されたときには、tweetsテーブルの関連するレコードも削除して、整合性が保たれるようにすべき。


そこで、ユーザーに紐づくツイートの内容は、ユーザーが削除されたときに一緒に削除されるようにdependent: :destroyを使う。

app\models/user.rb

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :tweets, dependent: :destroy
end


これで、ユーザー(シモベNo.1:a@a)を削除した時に、usersテーブルからユーザーが削除されると同時に、tweetsテーブルからもシモベNo.1がつぶやいたレコードが消える。

シモベNo.3のツイートが残っているが、これはdestroyを入れる前にユーザーを消したから、当然残ったまま。

sqlite> select id, email from users;
4|b@b   
sqlite> select id, body, user_id from tweets;
6|Cの投稿1つ目|3
9|お皿を洗っていると、足にお尻を乗せてくる|4
10|ネコ、昨日の水絶対飲まない(賢い!)|4
11|そこにいるだけでカワイイ!|4
sqlite>