質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

Q&A

解決済

1回答

3073閲覧

Laravel8 ソフトデリートが上手くいきません。

rousan

総合スコア2

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

0グッド

0クリップ

投稿2021/01/19 19:11

編集2021/01/20 09:29

1.前提・実現したこと

Laravelに標準装備されている認証機能「Auth」でユーザーの登録・ログイン・ログアウトは可能な状態です。ユーザーの削除機能はソフトデリート(論理削除)したいと思い、下記のReaDoubleというサイトを参考にしながらコードを書きました。

ReaDouble

その他参考サイト

2.発生している問題・エラーメッセージ

deleted_at列に削除した日時が保存されているのに、ソフトデリートしたはずのユーザーアカウントで普通にログインやツイートが出来てしまいます。

Eloquentは、データベースから実際にレコードを削除するだけでなく、モデルを「ソフトデリート」することもできます。モデルがソフト削除されても、実際にはデータベースから削除されません。代わりに、モデルに「deleted_at」属性がセットされ、モデルを「削除」した日時が保存されます。(引用元:ReaDouble)

3.該当のソースコード

//database/migrations/2021_01_19_213508_add_column_soft_deletes_users_table.php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddColumnSoftDeletesUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { $table->softDeletes(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->dropSoftDeletes(); }); } }
//app/Models/Users.php <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Users extends Model { use HasFactory; use SoftDeletes; protected $table = 'users'; }
//app/Http/Controllers/AccountController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Users; use \App\Models\Tweet; use Illuminate\Support\Facades\Auth; class AccountController extends Controller { public function deleteData(Request $request) { $user = Users::find($request->user_id); $user->delete(); $tweets = Tweet::latest()->get(); return view('timeline',[ 'tweets' => $tweets, ]); } }
//resources/views/timeline.blade.php //関係ある箇所のみ <form action="{{route('delete')}}" method="post"> @csrf <input type="hidden" name="user_id" value="{{Auth::user()->id}}"> <button type="submit">退会する</button> </form>
//routes/web.php //関係ある箇所のみ Route::post('/timeline/softdelete', [App\Http\Controllers\AccountController::class, 'deleteData'])->name('delete');

4.自分で調べたことや試したこと

他にも下記のサイト等いくつか調べましたが、これらの内容だと特に問題なさそうなので、何故ソフトデリートされたはずのデータでログインやツイートが出来てしまうのか原因が分かりません。

参考サイト1

参考サイト2

5.使っているツールのバージョンなど補足情報

OS Mac
PHP 7.3.11
Laravel 8.18.1

追記(m.ts10806様ご確認お願いします)

//app/Http/Controllers/Auth/LoginController.php(認証時) //(変更前)関係ある箇所のみ protected $redirectTo = 'timeline'; //(変更後)関係ある箇所のみ protected function redirectTo() { if (Auth::user()->deleted_at == null) { return 'timeline'; }else{ Auth::logout(); return 'timeline'; } }
//TimelineController(投稿時) //今回のWebアプリはログインユーザーのみがツイートできる前提なので、実際は上記の認証時の変更のみで大丈夫であり、この投稿時の変更は必要ないと考えています。 //(変更前)関係ある箇所のみ public function postTweet(Request $request) { $request->validate([ 'tweet' => 'required|max:140', ]); Tweet::create([ 'user_id' => Auth::user()->id, 'name' => Auth::user()->name, 'tweet' => $request->tweet, ]); return back(); } //(変更後)関係ある箇所のみ public function postTweet(Request $request) { $request->validate([ 'tweet' => 'required|max:140', ]); if(Auth::user()->deleted_at == null) { Tweet::create([ 'user_id' => Auth::user()->id, 'name' => Auth::user()->name, 'tweet' => $request->tweet, ]); } return back(); }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2021/01/19 19:26

認証時、投稿時に「deleted_atがnullである」というのはどこに含みましたか?
rousan

2021/01/20 10:03 編集

お返事ありがとうございます! 認証時、投稿時に「deleted_atがnullである」というのは全く考慮していませんでした。 それに対して素人なりに考えたコードを質問内容の最後に追記させていただきました。 ソフトデリートとはdeleted_at列に削除した日時が保存されるだけでは意味がなく、追記のように認証時や投稿時にdeleted_atの値で処理を判定する必要があるということで合っていますでしょうか? 一応、追記のコードならdeleted_at列に削除した日時が保存されているユーザーはログインしようとしてもゲストとしてtimeline.blade.phpが表示されるだけになりました。
hentaiman

2021/01/20 09:32

> deleted_atの値で処理を判定する必要がある SQL直書きしてるんでなければ自前で判定処理を書く必要ナッシング
rousan

2021/01/20 10:03 編集

お返事ありがとうございます! timeline.blade.phpからuser_idをPOST送信し、AccountController.phpにてレコード検索した結果をdeleteすることで、deleted_at列に削除した日時が保存されていると思っているのですが、これがSQL直書きということで上手くいかない原因なのでしょうか?
m.ts10806

2021/01/20 09:57

SQL直書き個所は見当たりませんね。 モデル/Eloquentの機能を使ってるように見えます。
rousan

2021/01/20 10:02 編集

普通なら追記のコードは必要なく、私の場合は何故かソフトデリートが上手くいかないので追記のコードが必要ということでしょうか?
m.ts10806

2021/01/20 10:34

「deleted_at列に削除した日時が保存されている」とあるので ソフトデリートは「できている」ように見えますが、問題はソフトデリートの結果可否ではないと思います。
rousan

2021/01/20 14:44

そもそもソフトデリートでユーザー削除というのが間違いなのでしょうか。。。実際はどのような方法でユーザー削除をされることが多いのでしょうか?
hentaiman

2021/01/20 21:22

それはポリシー次第です。 ソフトデリートでもDELETEでもどちらでも構いません。 コード見るのが怠い(読んでない)ので回答は出来ません、ソフトデリート自体は出来ているので取得するSQLが正しくないと思われるので、まず発行されているSQLを確認しましょう で、おかしいSQLを発行していると推定出来た個所を修正するのです。
rousan

2021/01/23 10:02 編集

自分なりに調べてみても「SQLが正しくないと思われるので、まず発行されているSQLを確認しましょう」の意味がよく分かりませんでした。お手数おかけして申し訳ございませんが、どのようにしたらいいのかもう少し教えていただけないでしょうか?本当はソフトデリートが出来ているならそれだけでログインやツイートはできないはずという意味でしょうか?
m.ts10806

2021/01/23 09:48

そのまま「Laravel 発行SQL 確認」で検索してみればいいのでは・・・
hentaiman

2021/01/23 10:17

> 本当はソフトデリートが出来ているならそれだけでログインやツイートはできないはずという意味でしょうか? ちゃいます。実際に実行されているSQLがSoftDeletesされているか(deleted_at)が埋まっているかどうか関係無しにSELECTしているという事です。 で、SQLの確認についてはmtsさんのコメントの通りlaravelの機能を調べてデバッグログとして出しても良いし、DB側のログ出力機能を使っても良いです。
rousan

2021/01/23 12:04

SQLのselect文にて、既に論理削除されたレコードを除く条件が必要ということで合っていますでしょうか?
hentaiman

2021/01/23 12:12 編集

SQL直書きを言っているなら違うけど・・・試しもしない段階で何度も聞かれるのも面倒くさいからとりあえずログ見たら?
rousan

2021/01/23 14:41

何度もすみません。TimelineControllerに、$sql = Users::where('id',1)->toSql(); var_dump($sql);と追記したところ「string(69) "select * from `users` where `id` = ? and `users`.`deleted_at` is null"」と確認できたのですが、IS NULL演算子でdeleted_atがnullを探しているように見えます。こういうことではないのでしょうか?
hentaiman

2021/01/23 14:58

それならソフトデリートをちゃんと見てますね それで結果がおかしいのなら別の箇所で意図しない動作をしてるんじゃないでしょうか?
rousan

2021/01/23 15:33

Authのログイン認証がどこでどのようにされているのかを調べていて、勘違いかもしれませんがvendor\laravel\ui\auth-backend\AuthenticatesUsers.phpなのかな?と思っていても初学者には解読が難しく。。。他に何がおかしい可能性が考えられますでしょうか。
guest

回答1

0

ベストアンサー

deleted_at列に削除した日時が保存されているのに、ソフトデリートしたはずのユーザーアカウントで普通にログインやツイートが出来てしまいます。

Laravel以前の話をします.

m.ts10806さんのおっしゃるようにソフトデリートつまり論理削除というのは削除したかのように振る舞い,データを扱うことです.

削除したかのような振る舞いを行っているだけなのでもちろんそのデータも参照することが可能です.よってログインできるのは当然です.もし論理削除されたデータを参照したくないのであればフラグから削除されているデータを判定しはじかなければなりません.

例えば,ユーザがブログを投稿する機能があるとするならば論理削除したはずユーザの投稿からユーザ名が表示されてしまうといったケースも考えられますし,論理削除した際に登録したメールアドレスは再度新規登録する際にユニークではなくなってしまうので登録もできません.

上記の項目を加味した上で本当にユーザに関する削除は論理削除が適切なのか物理削除が適切なのか考えて設計,諸諸の処理を行ってください.

投稿2021/01/20 15:20

kai0310

総合スコア2070

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kai0310

2021/01/20 15:21

どちらを使うかは要件次第です.
rousan

2021/01/23 09:37

ご回答ありがとうございます。 論理削除では再度新規登録する際に登録できないという考えがありませんでした。 自分なりに考えたのですが、論理削除ではなく物理削除で、その際に退会者情報(ユーザーID、名前、メールアドレス)を別の退会者情報専用のテーブルにsaveしてから退会処理をするのはどうかと考えました。 ※もしも何か問題を起こした方が退会してしまった場合に、退会者情報が有ったほうがいいのではないかと考えました。 無知で申し訳ございませんが、この考え方は特におかしなものではないでしょうか?
m.ts10806

2021/01/23 09:48

結局設計・要件次第の話。作る人が決めることですね。
kai0310

2021/02/16 05:14 編集

> 別の退会者情報専用のテーブルにsaveしてから退会処理をする 別のテーブルに移動させて保存するというのはアンチパターンになります。ただ、要件次第ですのでその様な管理が良いと思うのであれば LGTM です
rousan

2021/01/23 12:06

ありがとうございます。LGTMの意味も初めて知りました。勉強になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問