Fippiyのプログラム学習内容アウトプットBlog

日々の学習内容をアウトプットして振り返りを実施する。

Laravel開発、所有書籍登録の重複登録を防ぐ

バリデーション設定によるエラーチェック方法を実装していましたが、問題として残っていた箇所を続けて直しておくことにしました。

所有書籍登録時における重複登録を防ぐ処理を追加します。

今回の目的

所有書籍登録時の重複登録を防ぎ、同じデータが登録されないようにする

なぜやるか

重複登録されてしまう事象を確認しており、その現象を回避できるようにバリデーションによる重複登録拒否を必須化するため

やりたいこと

書籍情報の重複登録を防ぐ

やったこと

  • 重複登録防止の既存対策を確認する
  • 問題点を確認する
  • バリデーションによる重複登録防止を実装する

実施内容

所有書籍登録時の課題

既存対策として実施した内容

当初考えていた手順として所有書籍を登録する時は、所持していないタイトルのみ表示することにしていました。

こうすることで、所持済みの物はそもそも登録リストに表示がされないのでこれで問題ない…と考えていました。

問題点

しかし、実際に画面操作をしていて気づいたのですが、登録ボタンを続けて何度も押して全ての本を登録できるか実施していたところ、画面遷移する前に続けてボタンを押すと結果として同じ本が登録されている状況になっていました。

早い話が連打すると同じ本が登録できる状態です。

 

これを防止するために、やはりバリデーションによるチェックを実施して、重複時はエラーとすることにしました。

 

バリデーションを追加する 

単純なものから設定して動作を確認する

Propertyテーブルに登録済みの本があれば除外する(ユニーク)設定をしてみました。

# ~/app/Property.php

public static $createPropertyRules = array(
'bookdata_id' => 'required|unique:properties,bookdata_id
);

メールアドレスなどで設定する方法と同じです、同一の物があればエラーとして返します。

しかしこれでは問題が残ってしまいます。

Properyテーブルはログインユーザーの所有書籍を保存している為、単純に本のidだけで作成してしまうと、他人が同じ本を登録しているとエラーになります。

これでは使い物にはなりません…。

 

そこで、特定のユーザー情報に対して登録しようとする本がユニークである…といった条件に書き直してみました。

# ~/app/Property.php

public static $createPropertyRules = array(
'bookdata_id' => 'required|unique:properties,bookdata_id,user_id,1'
);

条件の後ろにuser_idとその番号を設定しました。しかしこれでもエラー表示ばかりで動作はしませんでした。 

  

さらに条件を調べてみたところ、こちらを参考にさせて頂きました、ありがとうございます。

tdsen.blog.jp

これに基づき、記述を変更してみました。

# ~/app/Property.php

public static $createPropertyRules = array(
'bookdata_id' => 'required|unique:properties,bookdata_id,NULL,user_id,user_id,1'
);

データがNULLでないレコードを対象と追加しています。こうすることで、user_idが1の情報にたいしてのbookdata_idのユニーク情報という設定ができました。

 

後は、ユーザーidが1と固定になっているので、これを常にログインユーザーとして動作してくれるように修正します。

# ~/app/Property.php

public static $createPropertyRules = array(
'bookdata_id' =>
 'required|unique:properties,bookdata_id,NULL,user_id,user_id,'.Auth::user()->id,
);

しかしこれでは動作しませんでした、Authデータが取得できていません。

 

動作させる為に一工夫する

この時、ルールを記入していたモデルの直前のコードを見てふと気がつきました。

# ~/app/Property.php

public function scopeUserNothaveBook()
{
$haveProperties = Property::where('user_id', [Auth::user()->id])->get('bookdata_id');
$notProperties = Bookdata::whereNotIn('id', $haveProperties)
->get();
return $notProperties;
}

ユーザーが所持していない本を表示するためのスコープです。

ここではAuthによる情報がきちんととれており、動作もしていました。

 

ルール設定としての書き方とは異なるかもしれませんが、現在設定中のルールについてもスコープとして書き直して動作させてみることにしました。

 

# ~/app/Property.php

public function scopeCreatePropertyRules()
{
$createPropertyRules = array(
'bookdata_id' =>
 'required|unique:properties,bookdata_id,NULL,user_id,user_id,'.Auth::user()->id,
);
return $createPropertyRules;
}
 

中身はそのまま、スコープに載せ替えを実施してみました。

 

スコープとして書き換えたので、コントローラー側で記述を変更します。

# ~/app/Http/Controllers/PropertyController.php

public function store(Request $request)
{
// バリデーションチェック
$createPropertyRules = Property::PropertyRules();
$this->validate($request, $createPropertyRules);
 

これで所有書籍登録時のDBレコード重複チェックができるようになりました。

バリデーション設定として操作中のユーザーに限定して、ユニーク情報として登録できるかをチェックしています。

 

バリデーションの条件記述のバリエーションを増やすことができれば、より柔軟な対応ができそうですね。