Rails8の続き、今回はDB周りです。
Railsを知ったときの驚きと言えばなんといってもActiveRecord、いわゆるORMとして、DBの構造をクラスにマッピングする(しかもおおよそ自動で)ということで動的言語の醍醐味を見せつけてくれるものでした。
内部的な違いはもちろん当時と今で異なるでしょうが、それでも基本は変わっていないようです。
1
2
3
4
5
6
7
| % ./bin/rails generate model Product name:string
invoke active_record
create db/migrate/20250227023240_create_products.rb
create app/models/product.rb
invoke test_unit
create test/models/product_test.rb
create test/fixtures/products.yml
|
ということで、モデルProductに相当するクラスProductを作成しました、現時点では必須となるID要素以外ではname(文字列)を持つように設定差rています。
- マイグレーション向けのコードが
db/migrate
ディレクトリ以下に作られる - DB上のProductテーブルに対応するモデルクラスが
app/models/product.rb
に作られる - テスト用のコードも
test/models/product_test.rb
に作られる
各商品(Product)に対応するレコードのため、モデル名は単数形でないといけないよと言う注意書きも忘れずに、と。
マイグレーション用のコードを確認すると、以下のようになっています。
1
2
3
4
5
6
7
8
9
10
11
| # db/migrate/2025XXXXXXXX_create_products.rb
class CreateProducts < ActiveRecord::Migration[8.0]
def change
create_table :products do |t|
t.string :name
t.timestamps
end
end
end
|
内部的に必要となるカラムは裏で自動で作られるみたいなのでほとんど記述は無し、その上で必要となるname
カラムが作成時の引数から準備されています。
- テーブル名(=
products
)が複数形なのは要注目、商品(Product)の集合ですから複数形ですよね、と t.timestamps
により、created_at
とupdated_at
が自動で作られます、ともにdatetime
型とのことです
とりあえずこれで実際にマイグレーション実行、と。
1
2
3
4
5
| % ./bin/rails db:migrate
== 2025XXXX023240 CreateProducts: migrating ===================================
-- create_table(:products)
-> 0.0112s
== 2025XXXX023240 CreateProducts: migrated (0.0114s) ==========================
|
しれっとデータベースが準備されているようです。これはSQLiteですね。
1
2
3
4
5
6
7
8
9
| % ls storage
development.sqlite3
% sqlite3 storage/development.sqlite3
SQLite version 3.43.2 2023-10-10 13:08:14
Enter ".help" for usage hints.
sqlite> .table
ar_internal_metadata products schema_migrations
sqlite> # <- Ctrl-D
%
|
Rails8での大きな変更点のひとつが「SQLiteで十分にデプロイして本番に持って行ける」ということだそうです、これは便利そうですね。
つづいて"Rails Console"、昔はあったのかよくわかりませんが、Laravelにおけるartisan上で使うコンソールのようなものでしょうか。
1
2
3
4
| % ./bin/rails console
Loading development environment (Rails 8.0.1)
store(dev)> Rails.version # すごい、補完機能が動く
=> "8.0.1"
|
ここではこれしか使わないみたいなので、いったん抜けておきましょう(Ctrl-D
)。
つづいてモデル周り、ActiveRecordですね。
1
2
3
| # app/models/product.rb
class Product < ApplicationRecord
end
|
たったこれだけで、以下のことが伝わってしまうのが恐ろしい。
- Productクラスが基底クラス
ApplicationRecord
を継承している - Productクラスにより、その集合となるテーブルproductsを参照/更新することがはっきりする
- 基本の操作は(カスタマイズしなければ)自動で行われるし、フィールド(カラム)の情報は勝手にテーブル構造から吸い上げて準備してくれる
ほんと、ActiveRecordの衝撃は今も変わらずですね。
コンソールを使って確認してみましょう。
1
2
3
4
| % ./bin/rails console
Loading development environment (Rails 8.0.1)
store(dev)> Product.column_names
=> ["id", "name", "created_at", "updated_at"]
|
idフィールドは自動だし、nameはマイグレーションで追加されています。
その上でcreate_at/updated/atがもマイグレーション側で自動で追加されています。
こいつらがテーブルのチェックから自動で取得されているわけです。
テーブルに対するCRUD操作もこのままコンソールでチェックです。
C(reate)は、Productクラスからインスタンスを生成することになります。
1
2
3
4
5
6
7
8
9
10
| % ./bin/rails console
Loading development environment (Rails 8.0.1)
store(dev)> product = Product.new(name: "Tシャツ")
=> #<Product:0x00000001328ac7c0
...
store(dev)> product.save
TRANSACTION (0.4ms) BEGIN immediate TRANSACTION /*application='Store'*/
Product Create (13.3ms) INSERT INTO "products" ("name", "created_at", "updated_at") VALUES ('Tシャツ', '2025-02-27 03:04:16.507146', '2025-02-27 03:04:16.507146') RETURNING "id" /*application='Store'*/
TRANSACTION (1.4ms) COMMIT TRANSACTION /*application='Store'*/
=> true
|
さすが、SQLがバックで生成されて実行されました。
今回はここまで。