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?

【RUNTEQアプリウィーク】RailsとLaravelを比較しつつMVCを一通り実装してみた 環境構築〜投稿機能編

0
Posted at

はじめに

RubyonRails歴数ヶ月の筆者が、
一週間の期限でアプリを作るRUNTEQアプリウィークに挑戦しました。
また、新たな知識を付けるため、PHPおよびLaravelに挑戦しました。

「起承転結シャッフルストーリーメーカー」というアプリを題材に、
環境構築からMVC実装まで一通りの流れをRailsと比較しながら紹介します。

環境

  • Laravel 13.7.0
  • PHP 8.4
  • MySQL
  • Docker(Laravel Sail)
  • macOS

1. 環境構築(Laravel Sail)

Sailとは?

Laravel Sailは、DockerベースのLaravel開発環境です。
PHP・MySQL・Redisなど必要なものが全部入りで、自分でDockerfileを書く必要がありません。

# プロジェクト作成(PHP8.4を指定)
curl -s "https://laravel.build/shufflestory?php=84" | bash
cd shufflestory

# 起動
./vendor/bin/sail up

⚠️ 2026年5月時点ではlaravel.buildがデフォルトでPHP8.5を指定してしまうバグがあるので
compose.yamlcontextruntimes/8.4に修正してから
sail build --no-cacheしました。

マイグレーション実行

./vendor/bin/sail artisan migrate

http://localhostでLaravelのウェルカム画面が表示されれば成功です。

RailsとSailの比較

Rails Laravel Sail
環境構築 rails new curl -s laravel.build/... | bash
サーバー起動 rails server ./vendor/bin/sail up
コマンド実行 rails ... ./vendor/bin/sail artisan ...

Sailを使う場合、php artisanではなく./vendor/bin/sail artisanを使います。
入力するとエラーが出ます。


2. ルーティング設計

今回のアプリに必要なルートはこちらです。

// routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\StoryController;

Route::get('/',                [HomeController::class,  'index'])->name('home');
Route::get('/stories',         [StoryController::class, 'index'])->name('stories.index');
Route::get('/stories/create',  [StoryController::class, 'create'])->name('stories.create');
Route::post('/stories',        [StoryController::class, 'store'])->name('stories.store');
Route::get('/stories/{id}',    [StoryController::class, 'show'])->name('stories.show');
Route::get('/stories/shuffle', [StoryController::class, 'shuffle'])->name('stories.shuffle');

RailsとLaravelのルーティング比較

Rails Laravel
記述ファイル config/routes.rb routes/web.php
GET get '/stories', to: 'stories#index' Route::get('/stories', [StoryController::class, 'index'])
POST post '/stories', to: 'stories#store' Route::post('/stories', [StoryController::class, 'store'])
名前付きルート as: 'stories_index' ->name('stories.index')
ルート呼び出し stories_path route('stories.index')

ルート名について

Bladeテンプレートではroute()ヘルパーを使ってURLを生成できます。

<!-- URLを直書きしないURLが変わっても1箇所直すだけでOK -->
<a href="{{ route('stories.create') }}">投稿する</a>

3. コントローラー

作成コマンド

./vendor/bin/sail artisan make:controller HomeController
./vendor/bin/sail artisan make:controller StoryController

HomeController

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    public function index()
    {
        return view('home');
    }
}

RailsとLaravelのController比較

Rails Laravel
生成コマンド rails g controller Home sail artisan make:controller HomeController
ビュー返却 render 'home' return view('home')
リダイレクト redirect_to stories_path return redirect()->route('stories.index')
パラメータ取得 params[:title] $request->get('title')

StoryController

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\HomeController;
use App\Models\Story;

class StoryController extends Controller
{
    public function index()
    {
    // viewのstories.index.blade.php を表示
        return view('stories.index');
    }

    public function create()
    {
    // viewのstories.create.blade.php を表示
        return view('stories.create');
    }

    public function store(Request $request)
    {
    // フォームから送信されたデータを取得
        $title = $request->get('title');
        $author = $request->get('author');
        $intro = $request->get('intro');
        $develop = $request->get('develop');
        $conversion = $request->get('conversion');
        $ending = $request->get('ending');

    // storiesテーブルに取得したデータを保存
        $story = Story::create([
            'title' => $title,
            'author' => $author,
            'intro' => $intro,
            'develop' => $develop,
            'conversion' => $conversion,
            'ending' => $ending,
        ]);
        
        // 保存したデータのidを取得して、
        //showアクション(views/stories/show/{id})にリダイレクト
        
        return redirect()->route('stories.show', ['id' => $story->id]);
    }
    
    public function show($id)
    {
    // DBからidが一致するデータを1件取得
       $story = Story::find($id);
    // ビューに$storyを渡して表示
       return view('stories.show', ['story' => $story]);
                                      キー名    データ
    // Blade側では $story として使える
    }
}


4. モデルとマイグレーション

モデル作成

./vendor/bin/sail artisan make:model Story
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Story extends Model
{
    // 一括代入を許可するカラム(セキュリティ対策)
    protected $fillable = [
        'title',
        'author',
        'intro',
        'develop',
        'conversion',
        'ending',
    ];
}

$fillableとは?

Mass Assignment(一括代入)攻撃を防ぐセキュリティ機能です。
$fillableに書いたカラムだけcreate()での保存を許可します。

fillableがないと悪意あるユーザーがis_admin=trueを送れてしまう
fillableがあれば許可したカラムのみ保存される
セキュリティ的にこれは忘れず設定しましょう。

マイグレーション作成と実行

./vendor/bin/sail artisan make:migration create_stories_table
./vendor/bin/sail artisan migrate
public function up(): void
{
    Schema::create('stories', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->string('author');
        $table->text('intro');
        $table->text('develop');
        $table->text('conversion');
        $table->text('ending');
        $table->timestamps(); // created_at, updated_at
    });
}

RailsとLaravelのモデル・マイグレーション比較

Rails Laravel
モデル生成 rails g model Story sail artisan make:model Story
マイグレーション生成 rails g migration CreateStories sail artisan make:migration create_stories_table
マイグレーション実行 rails db:migrate sail artisan migrate
1件取得 Story.find(id) Story::find($id)
全件取得 Story.all Story::all()
作成 Story.create(params) Story::create([...])
ORM名 ActiveRecord Eloquent

5. ビュー(Bladeテンプレート)

作成コマンド

# viewファイルの storys.create.blade.phpを作成します
 ./vendor/bin/sail artisan make:view stories.create

# Controllerファイルも作れます。 StoryController.phpを作成します
./vendor/bin/sail artisan make:controller StoryController

# ModelもOK
./vendor/bin/sail artisan make:model  Story

# マイグレーションファイル作成の際はLaravelの命名規則に従い_(アンダーバー)を使用
./vendor/bin/sail artisan make:migration create_stories_table

ストーリークリエイトビュー
スクリーンショット 2026-05-02 15.15.16.png

ストーリーテーブル
スクリーンショット 2026-05-02 16.16.15.png

作成するとこんなメッセージが流れます。

トップページ(home.blade.php)

<div>
    <h1>ShuffleStory</h1>
    <p>起承転結を投稿して、シャッフルしてオリジナルストーリーを作ろう!</p>
    <a href="{{ route('stories.create') }}">物語を投稿する</a>
    <a href="{{ route('stories.index') }}">物語一覧を見る</a>
</div>

投稿フォーム(stories/create.blade.php)

<form method="POST" action="{{ route('stories.store') }}">
    @csrf
    <div>
        <label for="title">タイトル</label>
        <input type="text" id="title" name="title" required>
    </div>
    <div>
        <label for="intro"></label>
        <textarea id="intro" name="intro" required></textarea>
    </div>
    <div>
        <label for="develop"></label>
        <textarea id="develop" name="develop" required></textarea>
    </div>
    <div>
        <label for="conversion"></label>
        <textarea id="conversion" name="conversion" required></textarea>
    </div>
    <div>
        <label for="ending"></label>
        <textarea id="ending" name="ending" required></textarea>
    </div>
    <button type="submit">投稿する</button>
</form>

RailsとLaravelのビュー比較

Rails(ERB) Laravel(Blade)
ファイル拡張子 .html.erb .blade.php
変数表示 <%= @story.title %> {{ $story->title }}
CSRFトークン <%= csrf_meta_tags %> @csrf
ルートURL stories_path route('stories.index')

6. データ確認(tinker)

Railsのrails consoleに相当するのがtinkerです。

./vendor/bin/sail artisan tinker

# 全件取得
> App\Models\Story::all();

# 1件取得
> App\Models\Story::find(1);

まとめ

RailsとLaravelは思想が非常に似ており、
Rails経験者であれば比較的スムーズに入れました。
主な違いは以下の通りです。

概念 Rails Laravel
言語 Ruby PHP
コマンド rails artisan
変数 @story $story
プロパティアクセス story.title $story->title
ビュー ERB Blade
ORM ActiveRecord Eloquent
設定ファイル 規約優先 config/に明示的

次のステップとして、
シャッフル機能・一覧表示・バリデーションを実装していく予定です。

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?