3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LaravelでRailsチュートリアル【第三章】

Posted at

これは何?

僕自身、Ruby on Railsを使ってWebアプリ開発をしてきましたが、転職をきっかけにLaravelを使うことになりました。
そこで、Railsエンジニアの間では登竜門のような扱いになっているRailsチュートリアルを、Laravelでやってみたら、Laravelにも慣れるし、Railsとの違いが分かって面白いんじゃないかと思って始めたのがこの企画です。

Railsチュートリアルの第一章、二章は簡単なアプリを作り切って終わってしまうので、本格的に作り始める第三章からやっていきたいと思います。
また、本番環境扱いとしてAWSのEC2にデプロイしていきたいと思います。

新規プロジェクトの作成

Railsチュートリアルでは、新規プロジェクトの作成から行なっています。

Rails
rails _7.0.4.3_ new sample_app
Laravel
composer create-project laravel/laravel laravel_app

使っているバージョン情報は、以下の通りとなります。

使用バージョン
Laravel Framework 11.32.0
PHP 8.3.12 (cli) (built: Oct 7 2024 10:53:51) (NTS)

作業ブランチの作成

Railsチュートリアルに倣って、作業ブランチを作成していきます。

まずは、Gitを導入してmainブランチをGitHubにプッシュ

Terminal
git init
git add .
git commit -m "プロジェクト新規作成"
git remote add origin https://github.com/daigo175/Laravel-tutorial.git
git push origin main

次に、作業用ブランチを作っていきます。
git switch -c static-pages

Gitのバージョン
git version 2.39.5 (Apple Git-154)

3.2.1静的なページの生成

静的なページを表示するためのコントローラを作成していきます。

Rails
rails generate controller StaticPages home help
Laravel
php artisan make:controller StaticPagesController

この結果、Railsはstatic_pages_controller.rbhome.html.erbといったビューファイル、テストユニットやヘルパーなども作成されますが、Laravelにはそのようなジェネレータは無さそうです(私が知らないだけかも)

LaravelではStaticPagesController.phpが作成されます。
Railsはファイル名がスネークケース、 Laravelはアッパーキャメルケースとなっているのですね。

コラム 3.1.元に戻す方法

Railsには、コントローラーの生成を取り消すコマンドがあります。
rails destroy controller StaticPages home help
Railsのジェネレータは複数のファイルを一気に作成してくれる分、削除コマンドも用意されているのだと思います。

これはLaravelにはありませんが、Laravelは最低限のファイルが生成される分、取消よりも物理的に削除した方が早いのでしょうね。
逆にRailsは不要なファイルも一緒に作ってしまうし、それを防ぐには設定を書かないといけなかったりで、一長一短な気がします。

ルーティングの追加

コントローラを作成すると、Railsはオプションで渡したルーティングが自動的に追加されます。

config/routes.rb
Rails.application.routes.draw do
  get  "static_pages/home"
  get  "static_pages/help"
end

Laravelにも同等の定義を追加することにします。

routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\StaticPagesController;
 
Route::controller(StaticPagesController::class)->group(function () {
    Route::get('/static_pages/home', 'home');
    Route::get('/static_pages/help', 'help');
});

コントローラの編集

同様に、Railsは既にアクションが作成済となります。

app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
  def home
  end

  def help
  end
end

Laravelにも同様のアクションを作成することにします。

app/Http/Controllers/StaticPagesController.php
<?php

namespace App\Http\Controllers;

use Illuminate\View\View;

class StaticPagesController extends Controller
{
    // homeページを返却
    public function home(): View
    {
        return view('static_pages.home');
    }

    // helpページを返却
    public function help(): View
    {
        return view('static_pages.help');
    }

}

ビューの追加

こちらも同様、Railsではビューファイルが作成されています。

app/views/static_pages/home.html.erb
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
app/views/static_pages/help.html.erb
<h1>StaticPages#help</h1>
<p>Find me in app/views/static_pages/help.html.erb</p>

Laravelにも追加を行います。

Laravel
mkdir resources/views/static_pages
touch resources/views/static_pages/home.blade.php
touch resources/views/static_pages/help.blade.php

ビューの中身はRailsのそれと同様にしておきます。
そして、一度確認してみます。
php artisan serve

スクリーンショット 2024-11-20 16.52.26.png
スクリーンショット 2024-11-20 16.53.21.png

3.3テストから始める

(Railsチュートリアル)[https://railstutorial.jp/chapters/static_pages?version=7.0#sec-getting_started_with_testing]には、まず要件通りにテストコードを書いて、その後にテストが成功するよう作り上げていくというテスト駆動開発手法が載っています(但しTDDを推しているわけではない)

3.3.1最初のテスト

コントローラを作成した段階で、Railsはテストユニットも作成しています。

test/controllers/static_pages_controller_test.rb
require "test_helper"

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get static_pages_home_url
    assert_response :success
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
  end
end

今までと同様、Laravelでもテストユニットを新規作成していきます。
php artisan make:test StaticPageTest

tests/Feature/StaticPageTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class StaticPageTest extends TestCase
{
    /**
     * homeページへのアクセスが正常であること
     */
    public function test_the_home_page_returns_a_successful_response(): void
    {
        $response = $this->get('/static_pages/home');

        $response->assertStatus(200);
    }

    /**
     * helpページへのアクセスが正常であること
     */
    public function test_the_help_page_returns_a_successful_response(): void
    {
        $response = $this->get('/static_pages/help');

        $response->assertStatus(200);
    }

}

テストユニットができたら、テストを実行して、問題なくパスすることを確認します。

Rails
rails test
Laravel
php artisan test

3.3.2Red

Railsチュートリアルでは、今後aboutページを追加するにあたり、まず要件(失敗するテスト)から書いていきます。

test/controllers/static_pages_controller_test.rb
require "test_helper"

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get static_pages_home_url
    assert_response :success
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
  end

+ test "should get about" do
+   get static_pages_about_url
+   assert_response :success
+ end
end

Laravelにも同様に、失敗するテストを追加します。

tests/Feature/StaticPageTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class StaticPageTest extends TestCase
{
    /**
     * homeページへのアクセスが正常であること
     */
    public function test_home_page_returns_a_successful_response(): void
    {
        $response = $this->get('/static_pages/home');

        $response->assertStatus(200);
    }

    /**
     * helpページへのアクセスが正常であること
     */
    public function test_help_page_returns_a_successful_response(): void
    {
        $response = $this->get('/static_pages/help');

        $response->assertStatus(200);
    }

+   /**
+    * aboutページへのアクセスが正常であること
+    */
+   public function test_about_page_returns_a_successful_response(): void
+   {
+       $response = $this->get('/static_pages/about');
+
+       $response->assertStatus(200);
+   }

}

テストを実行してみると、想定通りにエラーとなります。
スクリーンショット 2024-11-21 8.42.24.png

3.3.3Green

Laravelでのテスト実行結果を見るとExpected response status code [200] but received 404.とあります。
Railsチュートリアル同様、ルーティングから追加していくことにします。

config/routes.rb
Rails.application.routes.draw do
  get  "static_pages/home"
  get  "static_pages/help"
+ get  "static_pages/about"
  root "application#hello"
end
routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\StaticPagesController;
 
Route::controller(StaticPagesController::class)->group(function () {
    Route::get('/static_pages/home', 'home');
    Route::get('/static_pages/help', 'help');
+   Route::get('/static_pages/about', 'about');
});

この状態でテストを実行するとError: Call to undefined method App\Http\Controllers\StaticPagesController::about()となり、StaticPagesControllerにaboutアクションが存在しないことがわかります。

こちらも追加していきます。

app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController

  def home
  end

  def help
  end

+ def about
+ end
end
app/Http/Controllers/StaticPagesController.php
<?php

namespace App\Http\Controllers;

use Illuminate\View\View;

class StaticPagesController extends Controller
{
    // homeページを返却
    public function home(): View
    {
        return view('static_pages.home');
    }

    // helpページを返却
    public function help(): View
    {
        return view('static_pages.help');
    }

+   // aboutページを返却
+   public function about(): View
+   {
+       return view('static_pages.about');
+   }
+   
}

この状態でテストを再実行するとInvalidArgumentException: View [static_pages.about] not found.となり、ビューが存在していないことがわかります。

こちらもRailsチュートリアル同様作成していきます。
touch resources/views/static_pages/about.blade.php

resources/views/static_pages/about.blade.php
<h1>StaticPages#about</h1>
<p>Find me in app/views/static_pages/about.html.erb</p>

ここまででテストを再実行すると、今度はパスします。
スクリーンショット 2024-11-21 8.54.28.png

3.4少しだけ動的なページ

このセクションでは、ページのtitleを動的に変更するということをしています。
まずは、失敗するテストを書いていきます。

test/controllers/static_pages_controller_test.rb
require "test_helper"

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Home | #{@base_title}"
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
    assert_select "title", "Help | #{@base_title}"
  end

  test "should get about" do
    get static_pages_about_url
    assert_response :success
    assert_select "title", "About | #{@base_title}"
  end
end

同等のテストをLaravelでも書いていきます。

tests/Feature/StaticPageTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class StaticPageTest extends TestCase
{
    // タイトルの固定文言部分を各テストケースで共有する
    private static $static_title;

    public static function setUpBeforeClass(): void
    {
        self::$static_title = "Ruby on Rails Tutorial Sample App";
    }

    /**
     * HTMLから<title>タグの内容を抽出
     *
     * @param string $html
     * @return string
     */
    private function extractTitle(string $html): string
    {
        preg_match('/<title>(.*?)<\/title>/', $html, $matches);

        return $matches[1] ?? '';
    }

    /**
     * homeページへのアクセスが正常であること
     */
    public function test_home_page_returns_a_successful_response(): void
    {
        $response = $this->get('/static_pages/home');
        $response->assertStatus(200);
        // ページ内容からタイトルを抽出
        $title = $this->extractTitle($response->getContent());
        $this->assertStringContainsString("Home | " . self::$static_title, $title);
    }

    /**
     * helpページへのアクセスが正常であること
     */
    public function test_help_page_returns_a_successful_response(): void
    {
        $response = $this->get('/static_pages/help');
        $response->assertStatus(200);
        $title = $this->extractTitle($response->getContent());
        $this->assertStringContainsString("Help | " . self::$static_title, $title);
    }

    /**
     * aboutページへのアクセスが正常であること
     */
    public function test_about_page_returns_a_successful_response(): void
    {
        $response = $this->get('/static_pages/about');
        $response->assertStatus(200);
        $title = $this->extractTitle($response->getContent());
        $this->assertStringContainsString("About | " . self::$static_title, $title);
    }

}

ここでsetUpBeforeClass()メソッドを使っています。

setUpBeforeClass()
テスト実行前に1度だけ呼び出されるメソッド
毎回呼び出すと冗長となってしまうテストデータの設定などに使用できる

各ビューファイルは、チュートリアルに沿って、<title>About | Ruby on Rails Tutorial Sample App</title>のように、固定文言を含むレイアウトに書き換えます。

AWS EC2にデプロイする

最後に、EC2インスタンスにデプロイを行います。
別記事を書いています↓

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?