~fvknk/bk

技術関連の備忘録

Rails チュートリアルを改めてやってみる 1-3章

概要

今までRails7を触ったことがなかったため、感触を確かめるのも兼ねて改めてRailsチュートリアルをやってみました。

railstutorial.jp

第1章

RailsチュートリアルではGitHub Codespaceを使用していますが、手元でDockerを用いて環境構築を行いました。

開発環境整備

まずは、Railsチュートリアル用のリポジトリをクローンします。 ディレクトリ名は今後の管理を楽にするため短いものへ変更しておきます。

 git clone https://github.com/yasslab/codespaces-railstutorial.git app

クローンが完了したら、appディレクトリ内にDockerfile、ルートにdocker-compose.ymlを配置して、docker compose upを実行します。
演習用環境なので、DBは立てるだけにしました。

FROM ruby:3

RUN apt-get update -qq

WORKDIR /app

COPY Gemfile Gemfile.lock /app/

RUN bundle install

CMD ["rails", "server", "-b", "0.0.0.0"]
services:
  db:
    image: esolang/sqlite3:latest

  app:
    build: ./app
    depends_on:
      - db
    ports:
      - "3000:3000"
    volumes:
      - ./app:/app

http://localhost:3000にアクセスすると、以下のようにチュートリアルの画面が表示されました。

bundle installDockerfileで実行済みなので、これで環境構築は完了になります。

演習でのrubyrailsbundleのバージョン確認はappコンテナにログインして実行しました。

$ docker compose exec app bash
root@933ea42ad62a:/app# ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]
root@933ea42ad62a:/app# rails -v
Rails 7.0.4.3
root@933ea42ad62a:/app# bundle -v
Bundler version 2.4.12

1.3.4 Hello, world! の演習

本編は書いてある通り行っただけなので割愛。 演習は下記のようにしました。

class ApplicationController < ActionController::Base

  def hello
    render html: '¡Hola, mundo!'
  end

  def goodbye
    render html: 'goodbye, world!'
  end
end
Rails.application.routes.draw do
  root "application#goodbye"
end

第2章

docker-compose.ymlDockerfileを使い回して環境を作りました。 railsコマンドはappコンテナ内ですべて実行しました。

演習

userの最初のmicropostを表示する課題については、条件をつけずにuserを新規作成すると以下のエラーが出たので、.exists?で紐づくmicropost存在確認をしました。

class UsersController < ApplicationController
  before_action :set_user, only: %i[ show edit update destroy ]

  # ...

  # GET /users/1 or /users/1.json
  def show
    @first_post = @user.microposts.first
  end

  # ...
end
<h1>Editing user</h1>

<%= render "form", user: @user %>
<%= render @first_post if @user.microposts.exists? %>

<br>

<div>
  <%= link_to "Show this user", @user %> |
  <%= link_to "Back to users", users_path %>
</div>

user作成・更新時のname,emailのバリデーションは以下のようにしました。

class User < ApplicationRecord
  has_many :microposts
  validates :name, presence: true
  validates :email, presence: true
end

第3章

2章と同じく、docker-compose.ymlDockerfileを使い回して環境を作りました。

Contactのページの追加はまず、テストコードに以下を追加しました。 この時点ではRedになります。

require "test_helper"

class StaticPagesControllerTest < ActionDispatch::IntegrationTest
  # ...

  test "should get contact" do
    get static_pages_contact_url
    assert_response :success
    assert_select "title", "Contact | #{@base_title}"
  end
end

static_pages_contact_urlがないとのことなので、routes.rbに追加します。

# rails test
Running 4 tests in a single process (parallelization threshold is 50)
Run options: --seed 31081

# Running:

..E.

Finished in 0.592640s, 6.7495 runs/s, 10.1242 assertions/s.

  1) Error:
StaticPagesControllerTest#test_should_get_contact:
NameError: undefined local variable or method `static_pages_contact_url' for #<StaticPagesControllerTest:0x00007f6e1a73d720>
    test/controllers/static_pages_controller_test.rb:28:in `block in <class:StaticPagesControllerTest>'

4 runs, 6 assertions, 0 failures, 1 errors, 0 skips
Rails.application.routes.draw do
  get 'static_pages/home'
  get 'static_pages/help'
  get 'static_pages/about'
  get 'static_pages/contact'
  root 'application#hello'
end

再度テストを実行すると、StaticPagesControllercontactアクションがないとのことなので追加します。

# rails test
Running 4 tests in a single process (parallelization threshold is 50)
Run options: --seed 36012

# Running:

E...

Finished in 0.620830s, 6.4430 runs/s, 9.6645 assertions/s.

  1) Error:
StaticPagesControllerTest#test_should_get_contact:
AbstractController::ActionNotFound: The action 'contact' could not be found for StaticPagesController
    test/controllers/static_pages_controller_test.rb:28:in `block in <class:StaticPagesControllerTest>'

4 runs, 6 assertions, 0 failures, 1 errors, 0 skips
class StaticPagesController < ApplicationController
  def home
  end

  def help
  end

  def about
  end

  def contact
  end
end

再度テストを実行すると、テンプレートがないとのことなので追加します。

# rails test
Running 4 tests in a single process (parallelization threshold is 50)
Run options: --seed 30891

# Running:

...E

Finished in 1.012043s, 3.9524 runs/s, 5.9286 assertions/s.

  1) Error:
StaticPagesControllerTest#test_should_get_contact:
ActionController::MissingExactTemplate: StaticPagesController#contact is missing a template for request formats: text/html
    test/controllers/static_pages_controller_test.rb:28:in `block in <class:StaticPagesControllerTest>'

4 runs, 6 assertions, 0 failures, 1 errors, 0 skips

ファイル追加後、再度テストを実行すると、タイトルがおかしいとのことなので、追加します。

# rails test
Running 4 tests in a single process (parallelization threshold is 50)
Run options: --seed 19525

# Running:

.F..

Finished in 0.693485s, 5.7680 runs/s, 11.5359 assertions/s.

  1) Failure:
StaticPagesControllerTest#test_should_get_contact [/app/test/controllers/static_pages_controller_test.rb:30]:
--- expected
+++ actual
@@ -1 +1 @@
-"Contact | Ruby on Rails Tutorial Sample App"
+"| Ruby on Rails Tutorial Sample App"
.
Expected 0 to be >= 1.

4 runs, 8 assertions, 1 failures, 0 errors, 0 skips
<% provide(:title, "Contact") %>

再度テストを実行すると、無事Greenになりました。

# rails test
Running 4 tests in a single process (parallelization threshold is 50)
Run options: --seed 49162

# Running:

....

Finished in 0.618450s, 6.4678 runs/s, 12.9356 assertions/s.

4 runs, 8 assertions, 0 failures, 0 errors, 0 skips

コンテンツを追加して、ブラウザでhttp://localhost:3000/static_pages/contactアクセスすると以下のように表示できました。

(もう少し段階を踏むのであれば、assert_response :successが通ることを確認してから、assert_select "title", "Contact | #{@base_title}"が通ることを確認するテストを追加するのでしょうが、今回はやることが明白だったためまとめました)