0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ポートフォリオ作成時メモ part6 ~投稿画面の作成①~

Last updated at Posted at 2024-11-17

はじめに

こんにちは、未経験からエンジニア転職を目指しているものです。
オンラインスクールで本格的に学習して6ヶ月目に入りました。PHP,Laravelを学習しポートフォリオを作成中です。ポートフォリオ作成手順及び、エラー内容を中心に記録していこうと思います。今回は投稿画面の作成を行いました。本投稿は流れのメモが重点になっておりますので、削除した部分や追加した部分の詳細は割愛致します。

ざっくりと投稿画面を作成

ワイヤーフレーム内容とは違いますが、まずは投稿画面が機能する状態まで作成してみました。

  • localhost/posts/create
    posts:create.png

投稿結果が反映されるような画面を作成

  • locallhost/posts
    posts.png投稿結果反映画面.png

エラーが発生

  • 添付のエラーが発生
    スクリーンショット 2024-11-19 21.11.56.png

  • エラーの原因
    投稿テーブルにcreated_atカラムが存在していなかった。
    このカラムはLaravelのlatest()メソッドがデフォルトで使用するため、created_atが無いとエラーになる。

対策内容

latest()の代わりに別の並び替え方法を使用
latest()メソッドはcreated_atをデフォルトで使用するが、別のカラムで並び替えを実施

  1. コントローラーの修正 PostController.phpのindexメソッドを以下のように修正し解決
public function index()
{
    $posts = Post::orderBy('id', 'desc')->get(); // id カラムで並び替え
    return view('posts.index', compact('posts'));
}

エラー2

実際に投稿機能を使用した時、添付のエラーが発生
スクリーンショット 2024-11-19 21.10.43.png

  • エラーの原因
    Posts テーブルに updated_at や created_at カラムが存在しない発生。
    Post::create() メソッドは、デフォルトでタイムスタンプ (updated_at と created_at) を保存しようとするが、それらのカラムがテーブルにないため、このエラーが発生。

対策内容

タイムスタンプは今回は不要な為、モデルでタイムスタンプを無効化し解決
app/Models/Post.phpに以下を追加

public $timestamps = false; // タイムスタンプを無効化

変更した部分

app/Http/Controllers/PostController.php

  <?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class PostController extends Controller
{
    // 投稿一覧を表示
    public function index()
    {
        $posts = Post::orderBy('id', 'desc')->get(); // id カラムで並び替え
        return view('posts.index', compact('posts'));
    }


    // 投稿フォームを表示
    public function create()
    {
        return view('posts.create');
    }

    // 投稿を保存
    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
            'preferred_gender' => 'nullable|string',
            'preferred_group_size' => 'nullable|string',
        ]);

        Post::create([
            'title' => $request->title,
            'content' => $request->content,
            'preferred_gender' => $request->preferred_gender,
            'preferred_group_size' => $request->preferred_group_size,
            'user_id' => Auth::id(),
        ]);

        return redirect()->route('posts.index')->with('success', '投稿が完了しました!');
    }
}

app/Models/Post.php

<?php

namespace App\Models;

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

class Post extends Model
{
    use HasFactory;

    // タイムスタンプを無効化
    public $timestamps = false;

    protected $fillable = [
        'title',
        'content',
        'preferred_gender',
        'preferred_group_size',
        'user_id',
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

database/migrations/2024_11_19_072137_create_posts_table.php

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id(); // 自動的にインクリメントされるID
            $table->string('title'); // 投稿タイトル
            $table->text('content'); // 投稿内容
            $table->string('preferred_gender')->nullable(); // 希望性別(nullを許容)
            $table->string('preferred_group_size')->nullable(); // 希望人数(nullを許容)
            $table->foreignId('user_id')->constrained()->onDelete('cascade'); // 投稿者のユーザーID(外部キー制約付き)
            // $table->timestamps(); // created_at と updated_at のタイムスタンプ
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('posts'); // posts テーブルを削除
    }
};

resources/views/posts/create.blade.php

<x-app-layout>
    <div class="max-w-7xl mx-auto p-6">
        <h2 class="text-2xl font-bold mb-4">新規投稿</h2>
        <form method="POST" action="{{ route('posts.store') }}">
            @csrf
            <div class="mb-4">
                <label for="title" class="block text-sm font-medium text-gray-700">タイトル</label>
                <input type="text" id="title" name="title" required class="block w-full border-gray-300 rounded-md shadow-sm">
            </div>
            <div class="mb-4">
                <label for="content" class="block text-sm font-medium text-gray-700">内容</label>
                <textarea id="content" name="content" rows="4" required class="block w-full border-gray-300 rounded-md shadow-sm"></textarea>
            </div>
            <div class="mb-4">
                <label for="location" class="block text-sm font-medium text-gray-700">活動場所</label>
                <input type="text" id="location" name="location" required class="block w-full border-gray-300 rounded-md shadow-sm">
            </div>
            <div class="mb-4">
                <label for="preferred_gender" class="block text-sm font-medium text-gray-700">希望性別</label>
                <select id="preferred_gender" name="preferred_gender" class="block w-full border-gray-300 rounded-md shadow-sm">
                    <option value="">指定なし</option>
                    <option value="male"></option>
                    <option value="female"></option>
                </select>
            </div>
            <div class="mb-4">
                <label for="preferred_group_size" class="block text-sm font-medium text-gray-700">希望人数</label>
                <select id="preferred_group_size" name="preferred_group_size" class="block w-full border-gray-300 rounded-md shadow-sm">
                    <option value="">指定なし</option>
                    <option value="one">一人</option>
                    <option value="two">二人</option>
                    <option value="three">三人</option>
                </select>
            </div>
            <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-md">投稿する</button>
        </form>
    </div>
</x-app-layout>

resources/views/posts/index.blade.php

<x-app-layout>
    <div class="max-w-7xl mx-auto p-6">
        <h2 class="text-2xl font-bold mb-4">投稿一覧</h2>
        @foreach ($posts as $post)
            <div class="border-b py-4">
                <h3 class="text-lg font-semibold">{{ $post->title }}</h3>
                <p class="text-gray-600">{{ $post->content }}</p>
                <p class="text-gray-500">活動場所: {{ $post->location }}</p>
            </div>
        @endforeach
    </div>
</x-app-layout>

routes/web.php

use App\Http\Controllers\ProfileController;
use App\Http\Controllers\AuthController; // AuthController をインポート
use App\Http\Controllers\PostController; // PostController をインポート
use Illuminate\Support\Facades\Route;

// ホーム画面ルート
@@ -25,4 +26,12 @@
Route::post('/login', [AuthController::class, 'showLoginForm'])->name('login');
Route::post('/login', [AuthController::class, 'login']);

// 投稿関連のルート
Route::middleware(['auth'])->group(function () {
    Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
    Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
    Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
});
require __DIR__.'/auth.php';

次回実施内容

  • 投稿画面の作成②

最後までご覧いただき本当にありがとうございました!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?