はじめに
Docker環境でのRailsによる開発でモデル作成、RSpecによるテストの実行の流れを備忘録として残しておきます。
フロントエンドとバックエンドを分けて開発しているのでそれに沿ったコマンドになっているのでご了承ください。
環境
- Ruby 3.2.9
- Rails 7.1.0
- RSpec 6.1
- FactoryBot 6.4
今回実装するCountryテーブルのER図
1. マイグレーションファイルの作成
まず、Countryテーブルを作成するマイグレーションファイルを生成します。
docker-compose exec backend rails generate migration CreateCountries
生成されたマイグレーションファイル (db/migrate/timestamp_create_countries.rb) を編集:
class CreateCountries < ActiveRecord::Migration[7.1]
def change
create_table :countries do |t|
t.string :name, null: false
t.string :hint_1
t.string :hint_2
t.string :hint_3
t.string :hint_4
t.string :flag_url
t.timestamps
end
end
end
マイグレーションの実行
docker-compose exec backend rails db:migrate
これで countries テーブルがデータベースに作成されます。
2. モデルファイルの作成
docker-compose exec backend rails generate model Country --skip-migration
-
--skip-migrationオプションを付けることで、既に作成済みのマイグレーションファイルと重複しないようにします。テーブルが重複しなければつける必要はありません。
筆者はこのオプションを忘れたため実行後に新しいマイグレーションファイルが自動生成され、既存の テーブル と重複してしまいました。その結果、マイグレーションを実行すると同じテーブルやカラムを二重に作ろうとしてエラーが発生しました。
生成された app/models/country.rb にバリデーションとアソシエーションを追加:
class Country < ApplicationRecord
# アソシエーション
has_many :quiz_attempts, dependent: :destroy
has_many :user_flags, dependent: :destroy
has_many :users, through: :user_flags
# バリデーション
validates :name, presence: true, uniqueness: true
validates :hint_1, presence: true
validates :hint_2, presence: true
validates :hint_3, presence: true
validates :hint_4, presence: true
validates :flag_url, presence: true
end
バリデーションの説明
-
name: 必須かつ一意 -
hint_1~hint_4: すべて必須 -
flag_url: 必須
3. FactoryBotファクトリーの定義
rails generate model コマンドで自動生成された spec/factories/countries.rb を編集:
FactoryBot.define do
factory :country do
sequence(:name) { |n| "Test Country #{n}" }
hint_1 { "This is hint 1" }
hint_2 { "This is hint 2" }
hint_3 { "This is hint 3" }
hint_4 { "This is hint 4" }
flag_url { "https://flagcdn.com/w320/jp.png" }
end
end
ポイント
-
sequence(:name)で名前の重複を防ぐ - すべての必須項目にデフォルト値を設定
4. RSpecテストファイルの作成
spec/models/country_spec.rb を編集:
require 'rails_helper'
RSpec.describe Country, type: :model do
describe 'associations' do
it { should have_many(:quiz_attempts).dependent(:destroy) }
it { should have_many(:user_flags).dependent(:destroy) }
it { should have_many(:users).through(:user_flags) }
end
describe 'validations' do
subject { create(:country) }
it { should validate_presence_of(:name) }
it { should validate_uniqueness_of(:name) }
it { should validate_presence_of(:hint_1) }
it { should validate_presence_of(:hint_2) }
it { should validate_presence_of(:hint_3) }
it { should validate_presence_of(:hint_4) }
it { should validate_presence_of(:flag_url) }
end
describe 'factory' do
it '有効なファクトリを持つこと' do
expect(build(:country)).to be_valid
end
end
end
テストの構成
- associations: アソシエーションの存在確認
- validations: バリデーションルールの検証
- factory: テスト用データが存在するか確認
5. テストの実行
Countryモデルのテストを実行
docker-compose exec backend rspec spec/models/country_spec.rb
実行結果
Country
associations
is expected to have many quiz_attempts dependent => destroy
is expected to have many user_flags dependent => destroy
is expected to have many users through user_flags
validations
is expected to validate that :name cannot be empty/falsy
is expected to validate that :name is case-sensitively unique
is expected to validate that :hint_1 cannot be empty/falsy
is expected to validate that :hint_2 cannot be empty/falsy
is expected to validate that :hint_3 cannot be empty/falsy
is expected to validate that :hint_4 cannot be empty/falsy
is expected to validate that :flag_url cannot be empty/falsy
factory
有効なファクトリを持つこと
Finished in 0.80733 seconds
11 examples, 0 failures
テストが通っていることが確認できました!
まとめ
Railsでモデルのテストを書く流れ:
- マイグレーション作成・実行 → テーブル作成
- モデルファイル作成 → バリデーションとアソシエーション定義
- ファクトリー定義 → テストデータの雛形作成
- テストファイル作成 → RSpecでテストケース記述
- テスト実行 → 動作確認
この流れを押さえておけば、他のモデルでも同様に実装できます。
