これは何?
僕自身、Ruby on Railsを使ってWebアプリ開発をしてきましたが、転職をきっかけにLaravelを使うことになりました。
そこで、Railsエンジニアの間では登竜門のような扱いになっているRailsチュートリアルを、Laravelでやってみたら、Laravelにも慣れるし、Railsとの違いが分かって面白いんじゃないかと思って始めたのがこの企画です。
Railsチュートリアルの第一章、二章は簡単なアプリを作り切って終わってしまうので、本格的に作り始める第三章からやっていきたいと思います。
また、本番環境扱いとしてAWSのEC2にデプロイしていきたいと思います。
新規プロジェクトの作成
Railsチュートリアルでは、新規プロジェクトの作成から行なっています。
rails _7.0.4.3_ new sample_app
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にプッシュ
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 generate controller StaticPages home help
php artisan make:controller StaticPagesController
この結果、Railsはstatic_pages_controller.rb
やhome.html.erb
といったビューファイル、テストユニットやヘルパーなども作成されますが、Laravelにはそのようなジェネレータは無さそうです(私が知らないだけかも)
LaravelではStaticPagesController.php
が作成されます。
Railsはファイル名がスネークケース、 Laravelはアッパーキャメルケースとなっているのですね。
コラム 3.1.元に戻す方法
Railsには、コントローラーの生成を取り消すコマンドがあります。
rails destroy controller StaticPages home help
Railsのジェネレータは複数のファイルを一気に作成してくれる分、削除コマンドも用意されているのだと思います。
これはLaravelにはありませんが、Laravelは最低限のファイルが生成される分、取消よりも物理的に削除した方が早いのでしょうね。
逆にRailsは不要なファイルも一緒に作ってしまうし、それを防ぐには設定を書かないといけなかったりで、一長一短な気がします。
ルーティングの追加
コントローラを作成すると、Railsはオプションで渡したルーティングが自動的に追加されます。
Rails.application.routes.draw do
get "static_pages/home"
get "static_pages/help"
end
Laravelにも同等の定義を追加することにします。
<?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は既にアクションが作成済となります。
class StaticPagesController < ApplicationController
def home
end
def help
end
end
Laravelにも同様のアクションを作成することにします。
<?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ではビューファイルが作成されています。
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
<h1>StaticPages#help</h1>
<p>Find me in app/views/static_pages/help.html.erb</p>
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
3.3テストから始める
(Railsチュートリアル)[https://railstutorial.jp/chapters/static_pages?version=7.0#sec-getting_started_with_testing]には、まず要件通りにテストコードを書いて、その後にテストが成功するよう作り上げていくというテスト駆動開発手法が載っています(但しTDDを推しているわけではない)
3.3.1最初のテスト
コントローラを作成した段階で、Railsはテストユニットも作成しています。
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
<?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 test
php artisan test
3.3.2Red
Railsチュートリアルでは、今後about
ページを追加するにあたり、まず要件(失敗するテスト)から書いていきます。
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にも同様に、失敗するテストを追加します。
<?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);
+ }
}
3.3.3Green
Laravelでのテスト実行結果を見るとExpected response status code [200] but received 404.
とあります。
Railsチュートリアル同様、ルーティングから追加していくことにします。
Rails.application.routes.draw do
get "static_pages/home"
get "static_pages/help"
+ get "static_pages/about"
root "application#hello"
end
<?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アクションが存在しないことがわかります。
こちらも追加していきます。
class StaticPagesController < ApplicationController
def home
end
def help
end
+ def about
+ end
end
<?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
<h1>StaticPages#about</h1>
<p>Find me in app/views/static_pages/about.html.erb</p>
3.4少しだけ動的なページ
このセクションでは、ページのtitleを動的に変更するということをしています。
まずは、失敗するテストを書いていきます。
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でも書いていきます。
<?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インスタンスにデプロイを行います。
別記事を書いています↓