この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:6
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: コントローラーにてモデルに値を格納してビューに渡す方法
SEOタイトル: Laravel MVC 基礎:Controller でモデルに値を保存し、View へ渡す方法(compact / with / 直接配列)

この記事の要点
  • Controller でモデル保存: Model::create($request->validated()) または $model = new Model; $model->fill(...); $model->save();
  • View への受け渡し 3 通り: compact() / 連想配列 / ->with()
  • Blade では {{ $post->title }} でアクセス(自動 HTML エスケープ付き)
  • Mass Assignment 対策: モデル側に $fillable または $guarded を必ず設定
  • 保存前に $request->validate([...]) でバリデーションを通すのが Laravel 標準

Laravel MVC の基本構造

MVC とは Model(DB との対話)・View(HTML 表示)・Controller(リクエスト処理)の三層に分ける設計パターンです。Laravel での典型的な流れ:

1) ブラウザ
   ↓ POST /posts
2) Route (routes/web.php)
   ↓ PostController@store
3) Controller (app/Http/Controllers/PostController.php)
   ・$request->validate(...)
   ・Post::create(...)             ← Model に保存
   ↓
4) View (resources/views/posts/show.blade.php)
   ・{{ $post->title }}            ← 表示
   ↑
5) ブラウザに HTML が返る

1. ルート定義

// routes/web.php
use App\Http\Controllers\PostController;

Route::get('/posts',         [PostController::class, 'index']);
Route::get('/posts/create',  [PostController::class, 'create']);
Route::post('/posts',        [PostController::class, 'store']);
Route::get('/posts/{post}',  [PostController::class, 'show']);

// 一括(リソースコントローラ)
Route::resource('posts', PostController::class);

2. モデル定義(Mass Assignment 対策込み)

# モデル + マイグレーション + コントローラ + リクエストを一括生成
php artisan make:model Post -mcr --requests
// app/Models/Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Post extends Model {
    use HasFactory;

    // ✅ 入力許可するカラムを明示(推奨)
    protected $fillable = ['title', 'body', 'user_id', 'published_at'];

    // または逆指定(基本これは使わない)
    // protected $guarded = ['id'];

    // 型キャスト
    protected $casts = [
        'published_at' => 'datetime',
        'meta'         => 'array',
    ];
}

$fillable または $guarded を設定しないと Mass Assignment(一括代入)で 例外が出ます。後述の Post::create($request->all()) も動きません。

3. Controller: モデルに値を保存する

// app/Http/Controllers/PostController.php
namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller {

    // 一覧
    public function index() {
        $posts = Post::orderBy('id', 'desc')->paginate(20);
        return view('posts.index', compact('posts'));
    }

    // 新規作成フォーム表示
    public function create() {
        return view('posts.create');
    }

    // 保存 ← 本記事のメイン
    public function store(Request $request) {
        // 1) バリデーション
        $validated = $request->validate([
            'title' => 'required|string|max:100',
            'body'  => 'required|string',
        ]);

        // 2) 認証ユーザを紐付け
        $validated['user_id'] = auth()->id();

        // 3) モデルに保存(4 通りのいずれか)
        // 方法 A: create で一発(fillable 必須)
        $post = Post::create($validated);

        // 方法 B: new + save
        // $post = new Post();
        // $post->fill($validated);
        // $post->save();

        // 方法 C: プロパティに直接代入
        // $post = new Post();
        // $post->title = $validated['title'];
        // $post->body  = $validated['body'];
        // $post->save();

        // 方法 D: リレーション経由
        // $post = auth()->user()->posts()->create($validated);

        // 4) View へリダイレクト or レンダリング
        return redirect()->route('posts.show', $post)
            ->with('success', '投稿しました');
    }

    // 詳細表示
    public function show(Post $post) {
        return view('posts.show', compact('post'));
    }
}

4. View に値を渡す 3 つの方法

// 方法 1: compact() —— もっとも一般的
$post = Post::find(1);
$comments = $post->comments;
return view('posts.show', compact('post', 'comments'));

// 方法 2: 連想配列で直接
return view('posts.show', [
    'post'     => Post::find(1),
    'comments' => Comment::where('post_id', 1)->get(),
]);

// 方法 3: with() チェーン
return view('posts.show')
    ->with('post', Post::find(1))
    ->with('comments', Comment::where('post_id', 1)->get());

// 方法 4: withXxx() マジックメソッド
return view('posts.show')
    ->withPost(Post::find(1))            // → $post
    ->withComments(Comment::all());      // → $comments

5. Blade テンプレートでの表示

{{-- resources/views/posts/show.blade.php --}}
@extends('layouts.app')

@section('content')
    

{{ $post->title }}

{{-- 自動 HTML エスケープ --}}

{!! nl2br(e($post->body)) !!}

{{-- e() でエスケープしてから改行変換 --}} 投稿者: {{ $post->user->name }}

コメント ({{ $comments->count() }} 件)

@forelse ($comments as $c)
{{ $c->user->name }}

{{ $c->body }}

@empty

まだコメントはありません

@endforelse @if (session('success'))
{{ session('success') }}
@endif @endsection

6. Form Request でバリデーションを分離(推奨)

Controller が肥大化するのを防ぐため、バリデーションは Form Request クラスに切り出すのが定石です:

php artisan make:request StorePostRequest
// app/Http/Requests/StorePostRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest {
    public function authorize(): bool {
        return auth()->check();
    }

    public function rules(): array {
        return [
            'title' => 'required|string|max:100|unique:posts,title',
            'body'  => 'required|string|min:10',
        ];
    }

    public function messages(): array {
        return [
            'title.required' => 'タイトルを入力してください',
            'title.unique'   => 'そのタイトルは既に使われています',
        ];
    }
}

// Controller
public function store(StorePostRequest $request) {
    $post = Post::create($request->validated() + [
        'user_id' => auth()->id(),
    ]);
    return redirect()->route('posts.show', $post);
}

7. 更新(update)

public function update(UpdatePostRequest $request, Post $post) {
    $post->update($request->validated());

    // 個別代入版
    // $post->title = $request->input('title');
    // $post->body  = $request->input('body');
    // $post->save();

    return redirect()->route('posts.show', $post)
        ->with('success', '更新しました');
}

Mass Assignment の罠

// ❌ $fillable 未設定の場合
$post = Post::create(['title' => 'hi', 'body' => 'foo']);
// → Illuminate\Database\Eloquent\MassAssignmentException

// ❌ 危険な書き方
// フォームに  を仕込まれると
Post::create($request->all());
// → is_admin まで保存されてしまう

// ✅ 安全な書き方
Post::create($request->only(['title', 'body']));
Post::create($request->validated());           // Form Request

$fillable と $guarded の違い

属性意味運用
$fillable = [...]許可するカラムを明示(ホワイトリスト)推奨
$guarded = [...]禁止するカラムを明示(ブラックリスト)非推奨(漏れがち)
$guarded = []すべて許可絶対避ける

FAQ

Q: Post::create() で「Add [field] to fillable」エラー
A: 該当カラムを $fillable 配列に追加してください。id, created_at, updated_at は自動なので不要。

Q: $post->title$post->getAttribute('title') の違い
A: 同じです。getAttribute は内部で呼ばれるメソッドで、Accessor を経由します。

Q: View で {{ $post }} と書くとどうなる
A: モデルが JSON シリアライズされて表示されます。$casts$hidden(除外したい属性)も反映されます。