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

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

Laravel開発、propertyテーブルをテストする【4】バリデーションを見直す

propertyテーブルが関係するテストを実装しています。

新規登録エラー時のテストまで完了したので、今回は編集エラー時のテストを実施していきます…が、

テスト実装時に未設定項目があったことに気がつきましたので、そちらの修正を先に行うことにしました。

今回の目的

所有書籍編集について、バリデーションが未設定であった為、設定を行う。

なぜやるか

バリデーションがないため、データ編集内容がどんな内容でも受付てしまうことを防ぐため。

やりたいこと

  • 編集データに対してバリデーションを設定する
  • 想定するデータでない場合はアラートを返し、編集不可とする

やったこと

  • バリデーション未設定アクションに対して、バリデーションを適用する
  • バリデーション設定が正しく動作することを確認する
  • バリデーション設定を見直す 

実施内容

編集アクションのバリデーションが設定されていない 

未設定に気づく

編集テストの実装を始める前にPropertyの編集アクションを再確認時に気づきました。

バリデーションが設定されていません。

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

public function update(Request $request, $id)
{
// バリデーションルール設定適用がいる
// 対象レコード取得
$property = Property::find($id);
// リクエストデータ受取
$form = $request->all();
// フォームトークン削除
unset($form['_token']);
// レコードアップデート
$property->fill($form)->save();
return redirect('/property');
}

しっかり適用がいると書いておきながら…。

気づいたので、テストの前にバリデーションを設定することにしました。

 

バリデーションを設定する

新規作成時のルールを適用させる

新規作成時に設定しているバリデーションと同一内容を設定しました。

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

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

これで、新規作成時と同様に同じユーザーでbookdata_idが重複しなければ編集可能となるはず…。

 

バリデーションルールはこんな内容でした。

# ~/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;
}

これで作成済みの編集テストを実施するも、テストが通らなくなりました。

本の情報自体を扱うBookdataテーブルでは新規作成・編集共に同じルールで問題なく動作しているのに対して、所有書籍情報を扱うPropertyテーブルでは新規作成・編集と同じルールを適用しても失敗しています。

もちろん、全く同じ構造ではないので…そこが問題かもしれません。

 

フォーム送信内容を確認する

そこで、編集時の動作を一度確認してみることにしました。

propertyテーブルの編集フォームはこんな内容です。

# ~/resources/views/property/edit.blade.php

<form action="/property/{{$form->id}}" method="post" enctype="multipart/form-data">
{{ csrf_field() }}
<input type="hidden" name="_method" value="PUT">
<div class="form-contents">
<div class="form-one-size">
<div class="form-input">
<div class="form-label">タイトル名</div>
<span class="form-input__input">{{$form->bookdata->title}}</span>
</div>
<div class="form-input">
<div class="form-label">所持数</div>
<div><input class="form-input__input" type="number" name="number"
 value="{{$form->number}}"></div>
</div>
<div class="form-input">
<div class="form-label">所持日</div>
<div><input class="form-input__input" type="date" name="getdate"
 value="{{$form->getdate}}"></div>
</div>
<div class="form-input">
<div class="form-label">フリーメモ</div>
<div><textarea class="form-input__detail" type="text" name="freememo">
 {{$form->freememo}}</textarea></div>
</div>
</div>
</div>
<div class="form-foot">
<input class="send" type="submit" value="登録">
</div>
</form>

フォームアクションとして/property/id番号/を指定することで対象のレコードを編集しています。タイトル名はpropertyテーブルからbookdataをリレーションしてタイトル表示をしています。

f:id:Fippiy:20190510144622p:plain

所有書籍情報編集フォーム

実際に編集フォームを確認すると、所有者が登録する情報はあくまで、所持書籍に対しての付加情報であり、書籍タイトル自体は変更しません。あくまで、所持済みの書籍に対しての情報を編集する…といった内容です。 

 

bookdata_id変更の処理はフォームには設定していない

所有書籍情報の変更ですので、所持数やコメントの変更が主な内容となりますが、タイトル名は変更しません。

タイトルが変わるということはそもそも所持している本が変わると言うこと、それでも変更が必要である場合であれば、所有情報でなく、本の情報自体を変更することになります。

また、タイトル変更を許可すると、意図しない変更リクエストをすることになるため、許可すべきではないと考えました。

 

フォーム指定で対象idは指定済み
<form action="/property/{{$form->id}}" method="post" enctype="multipart/form-data">

フォームアクションとして/property/id番号/が指定されているので、この時点で修正対象となるpropertyレコードは決定しています。

そして、編集内容は数やフリーメモとなるので、書籍タイトル自体は変更不要…つまりは書籍タイトルは何も変える必要はありません。

変更する必要がないデータはそもそも送信する必要はないのです。

 

エラーの内容を確認する

とはいえ、これでは解決しないので、一端bookdata_idをフォームを追加して動作するか確認しました。

bookdata_idがない場合、bookdata idは必須ですとエラー出力。

バリデーションルールでrequiredが設定されているので必須と言われます。

bookdata_idを入力した場合、同一idが既に存在しますとエラー出力。

バリデーションルールでuniqueが設定されています。

 

バリデーションの内容からするとこれは正常な動作です…が、編集なので、同じidの本は更新されてほしい。

 

バリデーションルールを見直す

ではどうやってこの状況から問題を解決するか?

既存ルールになにかもっといい設定方法がないか検討してみることにしました。

この際、こちらを参考にさせて頂きました、ありがとうございます。 

qiita.com

 

バリデーション設定方法を変更する

設定はこのように変更しました。

# ~/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/Property.php (変更後)

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

requiredをfilledに変更しました。

これにより、送信データがある場合のみチェックとすることにしました。

編集時のデータ処理としてはbookdata_idは送信されないので更新対象からは除外されます。対象外となればその他のデータが編集され、結果として想定していた動作が実現できます。

また同じルールを新規作成時にも適用していますが、こちらについては新規登録する登録書籍は必ず必要となるので、フォームからbookdata_idが送信されます。

そして、データが送信されるので従来通りのルールとしてデータチェックされることになります。

 

以上で、バリデーション未設定箇所についての対応が完了しました。

次回で編集時のエラーテストを実施していきます。