Laravel でレコード作成する場合にどの方法使うのか問題
状況
レコード作成する場合にいくつかやり方があるので,どの方法を使うのか迷う.
基本のレコード作成処理は以下のとおりとなる.
-
モデルでの
$fillable
(または$guarded
)プロパティの設定. -
コントローラなどでの
create()
メソッドの使用.
現時点の判断
-
モデルには
$fillable
(または$guarded
)プロパティを設定する. -
$request->user()
など使える場合は使う.そうでない場合はModel::create()
を使用する.
例 1:user_id のない posts テーブルのレコード作成
カラム名 | 型 | 備考 |
---|---|---|
id | unsignedBigInteger | 主キー |
post | string | 投稿内容 |
created_at | timestamp | 作成日時 |
updated_at | timestamp | 更新日時 |
この場合,アプリケーション側から設定できる値を指定(モデルの $fillable
)してコントローラなどで create() メソッドを使用する.
// app/Models/Post.php
$fillable = [
'post',
];
// app/Http/Controllers/PostController.php
public function store(Request $request)
{
$request->validate([
'post' => 'required|max:255',
]);
Post::create($request->only('post'));
return redirect()->route('posts.index');
}
他テーブルとのリレーションがない場合は,このようにシンプルに記述できる.
例 2:user_id のある posts テーブルのレコード作成
カラム名 | 型 | 備考 |
---|---|---|
id | unsignedBigInteger | 主キー |
user_id | unsignedBigInteger | 外部キー |
post | string | 投稿内容 |
created_at | timestamp | 作成日時 |
updated_at | timestamp | 更新日時 |
user_id などの外部キー(他テーブルの id)が含まれる場合には,不正な値で作成されないことが重要である.
create()
メソッドを使用してデータを作成することもできるが,その場合モデルの $fillable
プロパティに user_id など外部キーを追加する必要がある.
しかし,これではリクエストで送信されたデータで外部キーが設定できてしまうため,不正な値で作成される可能性がある.そのため,リクエストからユーザの情報を取得してリレーションを活用してデータを作成する,という流れになっている.
// app/Models/Post.php
$fillable = [
'post',
];
// app/Models/User.php
public function posts()
{
return $this->hasMany(Post::class);
}
// app/Http/Controllers/PostController.php
public function store(Request $request)
{
$request->validate([
'post' => 'required|max:255',
]);
$request->user()->posts()->create($request->only('post'));
return redirect()->route('posts.index');
}
-
$request->user()
の部分は現在認証されているユーザーのインスタンス(ユーザ情報)を取得する. -
posts()
は User のモデルから,1 対多の Post モデルを呼び出している.このときの Post モデルにはすでに user_id が設定された状態となる. -
create
Post モデルにデータを作成するためのメソッドである.
リクエストからユーザの情報を取得し,ユーザ id が指定済みの posts テーブルを用意してデータを作成する,と考えるとイメージしやすい.
例 3:user_id のある posts テーブルのレコード作成(リレーションを使わない場合 1)
リレーションを使わない場合は,以下のように記述する.create() メソッドを使用してデータを作成するが,fillable プロパティに外部キーを追加する必要がある.
// app/Models/Post.php
$fillable = [
'user_id',
'post',
];
// app/Models/User.php
public function posts()
{
return $this->hasMany(Post::class);
}
// app/Http/Controllers/PostController.php
public function store(Request $request)
{
$request->validate([
'post' => 'required|max:255',
]);
$newRecord = $request->merge(['user_id' => $request->user()->id])->all();
Post::create($newRecord);
return redirect()->route('posts.index');
}
例 4:user_id のある posts テーブルのレコード作成(リレーションを使わない場合 2)
以下のようにも記述できる.カラム数が多くなると冗長になるが,fillable プロパティに外部キーを追加する必要がない.
// app/Models/Post.php
$fillable = [
'post',
];
// app/Http/Controllers/PostController.php
public function store(Request $request)
{
$request->validate([
'post' => 'required|max:255',
]);
$post = new Post();
$post->post = $request->post;
$post->user_id = $request->user()->id;
$post->save();
return redirect()->route('posts.index');
}
まとめ
データ保護の観点から,$fillable
を使用した方法を使用したい.まずはモデルでリレーションを設定した上で,$request->user()
などを使用してリレーションを活用する方法を考えると良い.他のパターンでも Model::create()
を使用して作成するのが安全では.
以上だ( `・ω・)b
Discussion