4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【初心者向け🔰】Ruby on Rails チュートリアル 入門(モデルとマイグレーションの基本)

Last updated at Posted at 2023-03-25

概要

初めて Ruby on Rails で Web アプリ開発するための、入門編の記事。
Rails の基礎部分をなるべく絞って解説する。

手順 記事
#1 Rails の開発環境構築
#2 コントローラ・ビューの基本
#3 モデルとマイグレーションの基本(今回)
#4 DB のデータを画面に表示する
#5 画面から DB にデータを登録する
#6 画面から DB のデータをの更新・削除する

対象

  • Ruby on Rails で開発をしてみたい(しなければならない状況になった)方
  • HTML/CSS で簡単な Web ページを書いたことがある方
  • 「DB」「SQL」という言葉の意味を何となく理解できる方
  • 「REST API」や「GET」「POST」などを聞いたことがある方
  • Ruby もしくは、その他のオブジェクト指向のプログラミング言語に触れた方
    • 変数、四則演算、if 文、for 文、などは書いたことある
    • クラス、メソッド、インスタンス、などは聞いたことある

前提

macOS で作業する前提で書いてます。Windows の方は適宜、読み替えてください🙏

  • OS: macOS 13.12.1 "Ventura"
  • CPU: Intel
  • Ruby: v3.1.3
  • SQLite3: v3.39.5
  • Bundler: v2.4.9
  • Rails: v7.0.4

手順(データベースとテーブルを作る)

データベース(DB)の設定ファイル

Rails のDB設定は config/database.yml で設定する。

config/database.yml
# デフォルトの DB 接続設定
default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

# 開発環境の設定
development:
  <<: *default # デフォルトを引き継ぐ
  database: db/development.sqlite3

# テスト実行時の設定
test:
  <<: *default # デフォルトを引き継ぐ
  database: db/test.sqlite3

# 本番環境の設定
production:
  <<: *default # デフォルトを引き継ぐ
  database: db/production.sqlite3

👉 今回は、SQLite3 を利用するので、このままで OK。MySQL や PostgreSQL など別の DB を利用する場合は、ホスト名やユーザ名などの設定を追加する(具体的な設定内容は割愛)。
👉 デフォルトで設定している値は、各環境の箇所で同じキーを指定すれば値を上書き設定できる。

モデルを追加する

モデルとは、データ取得・新規追加・更新・削除など、DBのデータを使った直接的な処理はまとめる部分。

Rails ジェネレートコマンドで、モデル生成時の基本的な書き方

# 「カラム:データ型」はスペース区切りで複数指定できる。
rails g model モデル名 [カラム名:データ型]

👉 注意点は、この時の「モデル名」を必ず英語の "単数系" で指定すること(尚、後で出来あがるテーブル名は "複数形" になる)。

今回は、ユーザの「名前」と「年齢」を管理する User モデル を作成してみる。

# User モデル生成、カラムは「名前(文字列型)」「年齢(数値型)」
rails g model User name:string age:integer

すると、app 配下にファイル等が自動生成される。

プロジェクトディレクトリ/
  ├ app
  │ ├ models/
+ │ │  └ user.rb # モデル
  ├ db/
  | └ migrate/
+ |   └ 20230325081745_create_users.rb   # マイグレーションファイル
test/
    ├ fixtures/
+   |  └ users.yml   # テスト用サンプルデータを定義するフィクスチャファイル
    └ models/
+     └ user_test.rb   # モデルの単体テストファイル

👉 マイクレーションファイルは先頭に生成日時を表すタイムスタンプ(YYYYMMDDHHmmss 形式)が付与される。これは、万が一、複数のマイグレーションを再実行する時に、時系列にクエリが実行されるようにするため。
👉 上記の場合、2023年3月25日8時17分45秒(UTC:協定世界時)に作られたファイルことになる(日本だと9時間ズレている時間になる)。
👉 「フィクスチャ」「テスト」については今回割愛する

モデルの中身

現在は、モデルクラスのみが存在し、中身が空の状態。

app/models/user.rb
class User < ApplicationRecord
end

👉 基本的にすべてのモデルは、既に用意されている便利機能を利用するために ApplicationRecord を継承する。

マイグレーションとは

マイグレーションは、アプリのDB構造を変更するときに実行する機能で、Rails の場合は、db/migrate 配下にあるマイグレーションファイルを順次実行することで、それを実現する。

db/migrate/{TimeStamp}_create_users.rb
class CreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :name
      t.integer :age

      t.timestamps
    end
  end
end

👉 基本的にすべてのマイグレーションファイルは、既に用意されている便利機能を利用するために ActiveRecord を継承する。また、create_tablet.timestamps を自動付与する。
👉 create_table メソッドは、「id」というカラムを「オートインクリメントの主キー」として自動で追加してくれる。
👉 t.timestamps メソッドは、「created_at(レコード作成日)」「updated_at(レコード更新日)」カラムを自動で追加してくれる。

マイグレーション実行で DB スキーマ作成

マイグレーションファイルはあくまで設計図なので、まだ実際に DB の中身が出来たわけではない。

マイグレーションコマンドで、実際に DB にテーブルを生成する。

rails db:migrate

すると、今回は初回なので、以下のファイルが生成される。また、この時点で DB 内には 「users」 テーブルが生成されている

  db/
+  └ development.sqlite3   # SQLite の DB ファイル
+  └ schema.rb   # スキーマファイル

👉 development.sqlite3 は、SQLite3 の DB そのもの。schema.rb は、最新状態の「スキーマ」を記載したスキーマファイル。いずれも、初回のみ自動生成され、次回からは中身の更新になる。

スキーマとは

「スキーマ」は、DB のテーブルやカラム・データ型などの構造を定義するもの(レコードデータ自体は含まれない)。
Rails は、SQLite でも MySQL でも DB の種類に関係なく同じ DB 構造を持てるように、このスキーマファイル .rb 形式で持っている。
マイグレーションを順番に実行していった結果、出来上がる最新状態のスキーマが、schema.rb となるイメージ。

DB の中身を確認する(SQLite3)

尚、SQLite3 の DB の中身を確認する場合は、以下のコマンドで確認できる

# DB 接続コマンド(今回の database.yml 設定の場合)
sqlite3 db/development.sqlite3

👉 接続を終了する場合は、.quit、ヘルプは .help で表示できる。

テーブル一覧表示してみると、users テーブル が出来ている。

-- テーブル一覧表示
.tables

-- 結果(users が生成されている)
ar_internal_metadata   schema_migrations   users 

テーブル定義を確認すると、「id」「created_at」「updated_at」も追加されている。

-- users テーブルのスキーマ確認
.schema users

-- 結果
CREATE TABLE IF NOT EXISTS "users" (
  "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
  "name" varchar,
  "age" integer,
  "created_at" datetime(6) NOT NULL,
  "updated_at" datetime(6) NOT NULL
);

確認したら、接続終了する。

手順(Rails コンソールで DB にデータを追加する)

DB に直接データを投入するのも良いが、今回は 「Rails コンソール」 を使って、DB を操作する。まずは、以下のコマンドを実行。

# Rails コンソールを開く
rails console

# もしくは短縮系
rails c

すると、irbプロンプト というものが表示され、irb(main):001:0> という状態で待機する。

irb(main):001:0>

👉 Rails コンソール内では、直接 Ruby を書いて実行できる。つまり、ここで作成したモデルを使って DB にデータを登録したり削除したりもできる。
👉 irb(main): の後の 「001」 部分は "行数" なので、改行したり、処理を実施する度にカウントアップしていく。
👉 コンソールを終了する場合は、exit を実行

作成した User モデルを使って、現在の users テーブルの中身を見てみる。

# "モデル名.all" でテーブルのデータ全件取得(SELECT 文の発行)を実行できる
irb(main):001:0> User.all

  User Load (0.1ms)  SELECT "users".* FROM "users"
=> []    # 結果は空の状態

👉 マイグレーションで継承していた ActiveRecord.all などの DB 操作メソッドを持っている(モデルも、継承先の奥でこのモジュールを継承している)。

次に、レコードを1件追加してみる。

# "モデル名.create" でデータを追加
irb(main):002:0> User.create(name: "佐藤", age: 17)

  TRANSACTION (0.1ms)  begin transaction
  User Create (1.4ms)  INSERT INTO "users" ("name", "age", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "佐藤"], ["age", 17], ["created_at", "2023-03-25 13:25:12.192639"], ["updated_at", "2023-03-25 13:25:12.192639"]]        
  TRANSACTION (0.6ms)  commit transaction            
=> #<User:0x000000010c88c090 id: 1, name: "佐藤", age: 17, created_at: Sat, 25 Mar 2023 13:25:12.192639000 UTC +00:00, updated_at: Sat, 25 Mar 2023 13:25:12.192639000 UTC +00:00>

👉 create メソッドによって、SQL の INSERT 文 が発行され、レコードを一件追加した。

次に、create メソッド以外の方法で、もう1件データを追加してみる。まず、new メソッドで、モデルのインスタンスを生成する。

# User モデルのインスタンスを生成し、user という名前にする
irb(main):003:0> user = User.new(name: "鈴木", age: 17)

=> #<User:0x0000000106b2ba90 id: nil, name: "鈴木", age: 17, created_at: nil, updated_at: nil>

save メソッドを実行すると、新規作成したインスタンスで、新しいレコードを挿入する SQL が発行される

# save メソッドで INSERT 文が自動で実行される
irb(main):004:0> user.save

  TRANSACTION (0.1ms)  begin transaction
  User Create (0.4ms)  INSERT INTO "users" ("name", "age", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "鈴木"], ["age", 17], ["created_at", "2023-03-25 13:46:32.717614"], ["updated_at", "2023-03-25 13:46:32.717614"]]                 
  TRANSACTION (1.0ms)  commit transaction                       
=> true

👉 最初の方法との違いは、create メソッドだと INSERT 文を即実行するが、今回の場合は、インスタンスを作っただけでは SQL が実行されず save メソッドを実行して初めて INSERT が行われる点。

たった今作成した id: 2 のデータの年齢を、17 から 21 に変更してみる。

# インスタンスの "age" を指定して、21 を代入
irb(main):005:0> user.age = 21
=> 21

# save メソッドを実行すると、自動で UPDATE 文が発行される
irb(main):006:0> user.save
  TRANSACTION (0.1ms)  begin transaction
  User Update (0.4ms)  UPDATE "users" SET "age" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["age", 21], ["updated_at", "2023-03-25 13:51:41.434868"], ["id", 2]]
  TRANSACTION (1.1ms)  commit transaction                       
=> true

👉 save メソッドは、INSERT 専用の処理ではなく、既にあるデータなら UPDATE を自動で実行してくれる。

最終的に、2つのデータを生成したことを確認する。

# 全データ取得
irb(main):007:0> User.all

  User Load (0.2ms)  SELECT "users".* FROM "users"
=>                                                              
[#<User:0x000000010820c340 id: 1, name: "佐藤", age: 17, created_at: Sat, 25 Mar 2023 13:25:12.192639000 UTC +00:00, updated_at: Sat, 25 Mar 2023 13:25:12.192639000 UTC +00:00>,
 #<User:0x000000010820c1b0 id: 2, name: "鈴木", age: 21, created_at: Sat, 25 Mar 2023 13:46:32.717614000 UTC +00:00, updated_at: Sat, 25 Mar 2023 13:51:41.434868000 UTC +00:00>]

ここで、Rails コンソールを終了しておく。

おまけ

間違って余計なデータ(レコード)を作成してしまった場合は、対象のレコードを一度インスタンス化し、destroy メソッドを実行すると削除できる

# find メソッドで "id" を指定して、削除したいデータをインスタンス化する
irb(main):008:0> user = User.find(3)

  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
=> #<User:0x000000010ceabb10 id: 3, name: "間違い", age: 1, created_at: Sat, 25 Mar 2023 14:09:10.052578000 UTC +00:00, updated_at: Sat, 25 Mar 2023 14:09:10.052578000 UTC +00:00>

# destroy メソッドで DELETE 文を発行し、データ削除
irb(main):009:0> aaa.destroy

  TRANSACTION (0.1ms)  begin transaction
  User Destroy (1.6ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 3]]
  TRANSACTION (0.7ms)  commit transaction                      
=> #<User:0x000000010ceabb10 id: 3, name: "間違い", age: 1, created_at: Sat, 25 Mar 2023 14:09:10.052578000 UTC +00:00, updated_at: Sat, 25 Mar 2023 14:09:10.052578000 UTC +00:00> 

DB を完全削除してやり直したい場合は、Rails コンソールを抜けて、rails コマンドで実施

# DB を削除する (SQLite なら、DB ファイルが消える)
rails db:drop

👉 また rails db:migrate を実行すれば、データが空の状態で DB が生成される。

まとめ

  • モデルは、DB周辺処理を担当する部分
  • マイグレーションファイルを生成し、マイグレーションを実行すると DB が構築される
  • スキーマは DB の構造を定義するもの
  • スキーマファイルは、最新状態の DB スキーマを表す
  • Rails コンソールでは Ruby が実行でき、ActiveRecord のメソッドを利用することで DB 操作ができる
4
2
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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?