このガイドではActive Recordの基礎について説明します。
このガイドの内容:
Active Recordとは、MVCで言うところのM、つまりモデルに相当するものであり、ビジネスデータとビジネスロジックを表すシステムの階層です。Active Recordは、データベースに恒久的に保存される必要のあるビジネスオブジェクトの作成と利用を円滑に行なえるようにします。Active Recordは、ORM(オブジェクト/リレーショナルマッピング)システムに記述されている「Active Recordパターン」を実装したものであり、このパターンと同じ名前が付けられています。
パターン名としてのActive RecordはMartin Fowler『Patterns of Enterprise Application Architecture』という書籍に記述されています。Active Recordパターンにおいて、オブジェクトとは永続的なデータであり、そのデータに対する振る舞いでもあります。Active Recordパターンは、データアクセスのロジックを常にオブジェクトに含めておくことで、そのオブジェクトの利用者にデータベースへの読み書き方法を指示できる、という立場に立っています。
オブジェクト/リレーショナルマッピング(O/RマッピングやORMと略されることもあります)とは、アプリケーションが持つリッチなオブジェクトをリレーショナルデータベース(RDBMS)のテーブルに接続することです。ORMを用いると、SQL文を直接書く代わりにわずかなアクセスコードを書くだけで、アプリケーションにおけるオブジェクトの属性やリレーションシップをデータベースに保存することも、データベースから読み出すこともできるようになります。
Active Recordを完全に理解するには、リレーショナルデータベース管理システム(RDBMS)やSQL(構造化クエリ言語)についての知識が役に立ちます。これらについてもっと深く学びたい場合は、このチュートリアル(このチュートリアルも可)を参照するか、他の方法で学習しましょう。
Active Recordにはさまざまな機能が搭載されており、その中でも以下のものが特に重要です。
他のプログラミング言語やフレームワークでアプリケーションを作成すると、設定のためのコードを大量に書く必要が生じがちです。一般的なORMアプリケーションでは特にこの傾向があります。しかし、Railsで採用されているルール(規約)に従っていれば、Active Recordモデルの作成時に書かなければならない設定用コードは最小限で済みますし、設定用コードが完全に不要になることすらあります。これは「設定がほとんどの場合で共通ならば、その設定をアプリケーションのデフォルトにすべきである」という考えに基づいています。つまり、ユーザーによる明示的な設定が必要となるのは、標準のルールでは足りない場合だけです。
Active Recordには、モデルとデータベースのテーブルとのマッピング作成時に従うべきルールがいくつかあります。
Railsでは、データベースのテーブル名を探索するときに、モデルのクラス名を複数形にした名前で探索します。つまり、Book
というモデルクラスがある場合、これに対応するデータベースのテーブルは複数形の「books」になります。Railsの複数形化メカニズムは非常に強力で、不規則な語でも複数形/単数形に変換できます(person <-> peopleなど)。
モデルのクラス名が2語以上の複合語である場合、Rubyの慣習であるキャメルケース(CamelCaseのように語頭を大文字にしてスペースなしでつなぐ)に従ってください。一方、テーブル名はスネークケース(snake_caseなど、小文字とアンダースコアで構成する)にしなければなりません。以下の例を参照ください。
BookClub
)book_clubs
)モデル / クラス | テーブル / スキーマ |
---|---|
Article |
articles |
LineItem |
line_items |
Deer |
deers |
Mouse |
mice |
Person |
people |
Active Recordでは、データベースのテーブルで使うカラム名についても利用目的に応じたルールがあります。
外部キー(foreign key): このカラムはテーブル名の単数形_id
にする必要があります(例: item_id
、order_id
)。これらのカラムは、Active Recordがモデル間の関連付けを作成するときに参照されます。
主キー(primary key): デフォルトでは id
という名前のinteger
カラムがテーブルの主キーに使われます(PostgreSQLやMySQLではbigint
、SQLiteではinteger
)。Active Recordマイグレーションでテーブルを作成すると、これらのカラムが自動的に作成されます。
他にも、Active Recordインスタンスに機能を追加するカラム名がいくつかあります。
created_at
: レコード作成時に現在の日付時刻が自動的に設定されますupdated_at
: レコード作成時や更新時に現在の日付時刻が自動的に設定されますlock_version
: モデルにoptimistic lockingを追加しますtype
: モデルでSingle Table Inheritanceを使う場合に指定します関連付け名_type
: ポリモーフィック関連付けの種類を保存しますテーブル名_count
: 関連付けにおいて、所属しているオブジェクトの数をキャッシュするのに使われます。たとえば、Article
クラスにcomments_count
というカラムがあり、そこにComment
のインスタンスが多数あると、ポストごとのコメント数がここにキャッシュされます。これらのカラム名は必須ではありませんが、Active Recordで予約されています。特別な理由のない限り、これらの予約済みカラム名と同じカラム名の利用は避けてください。たとえば、type
という語はテーブルでSTI(Single Table Inheritance)を指定するために予約されています。STIを使わない場合であっても、予約語より先にまず「context」などのようなモデルのデータを適切に表す語を検討してください。
Active Recordモデルの作成は非常に簡単です。以下のようにApplicationRecord
クラスのサブクラスを作成するだけで完了します。
class Product < ApplicationRecord end
上のコードは、Product
モデルを作成し、データベースのproducts
テーブルにマッピングされます。さらに、テーブルに含まれている各行のカラムを、作成したモデルのインスタンスの属性にマッピングします。以下のSQL文(または拡張SQLの文)でproducts
テーブルを作成したとします。
CREATE TABLE products ( id int(11) NOT NULL auto_increment, name varchar(255), PRIMARY KEY (id) );
上のテーブルスキーマは、id
とname
という2つのカラムがある1つのテーブルを宣言しています。このテーブルの各行が、これら2つのパラメータを持つ特定の1つの製品名を表します。これで、次のようなコードを書けるようになります。
p = Product.new p.name = "Some Book" puts p.name # "Some Book"
Railsアプリケーションで別の命名ルールを使わなければならない場合や、レガシーデータベースを用いてRailsアプリケーションを作成しないといけない場合は、デフォルトの命名ルールを手軽にオーバーライドできます。
ApplicationRecord
は、有用なメソッドが多数定義されているActiveRecord::Base
を継承しているので、使うべきテーブル名をActiveRecord::Base.table_name=
メソッドで明示的に指定できます。
class Product < ApplicationRecord self.table_name = "my_products" end
テーブル名をこのように指定する場合、テストの定義ではset_fixture_class
メソッドを使い、フィクスチャ (my_products.yml) に対応するクラス名を別途定義しておく必要があります。
class ProductTest < ActiveSupport::TestCase set_fixture_class my_products: Product fixtures :my_products # ... end
ActiveRecord::Base.primary_key=
メソッドを用いて、テーブルの主キーに使われるカラム名を上書きすることもできます。
class Product < ApplicationRecord self.primary_key = "product_id" end
Active Recordでは、id
という名前を主キー以外のカラムで用いることはサポートされていません。
CRUDとは、4つのデータベース操作を表す「Create」「Read」「Update」「Delete」の頭字語です。Active Recordはこれらのメソッドを自動的に作成するので、テーブルに保存されているデータをアプリケーションで操作できるようになります。
Active Recordのオブジェクトはハッシュやブロックから作成できます。また、作成後に属性を手動で追加できます。new
メソッドを実行すると単に新しいオブジェクトが返されますが、create
を実行すると新しいオブジェクトが返され、さらにデータベースに保存されます。
たとえば、User
というモデルにname
とoccupation
という属性があるとすると、create
メソッドで新しいレコードが1件作成され、データベースに保存されます。
user = User.create(name: "David", occupation: "Code Artist")
new
メソッドでインスタンスを作成する場合、オブジェクトは保存されません。
user = User.new user.name = "David" user.occupation = "Code Artist"
上の場合、user.save
を実行して初めてデータベースにレコードがコミットされます。
最後に、create
やnew
にブロックを渡すと、そのブロックで初期化された新しいオブジェクトがyield
されます。
user = User.new do |u| u.name = "David" u.occupation = "Code Artist" end
Active Recordは、データベース内のデータにアクセスできる高機能なAPIを提供します。以下は、Active Recordが提供するさまざまなデータアクセスメソッドのほんの一部の例です。
# すべてのユーザーのコレクションを返す users = User.all
# 最初のユーザーを返す user = User.first
# Davidという名前を持つ最初のユーザーを返す david = User.find_by(name: 'David')
# 名前がDavidで、職業がコードアーティストのユーザーをすべて返し、created_atカラムで逆順ソートする users = User.where(name: 'David', occupation: 'Code Artist').order('created_at DESC')
Active Recordモデルへのクエリについて詳しくは、Active Recordクエリインターフェイスガイドを参照してください。
Active Recordオブジェクトを取得すると、オブジェクトの属性を変更してデータベースに保存できるようになります。
user = User.find_by(name: 'David') user.name = 'Dave' user.save
上のコードをもっと短く書くには、次のように、属性名と設定したい値をハッシュで対応付けて指定します。
user = User.find_by(name: 'David') user.update(name: 'Dave')
これは多くの属性を一度に更新したい場合に特に便利です。さらに、複数のレコードを一度に更新したい場合はupdate_all
というクラスメソッドが便利です。
User.update_all "max_login_attempts = 3, must_change_password = 'true'"
他のメソッドと同様、Active Recordオブジェクトを取得すると、そのオブジェクトをdestroy
してデータベースから削除できます。
user = User.find_by(name: 'David') user.destroy
複数レコードを一括削除したい場合は、destroy_by
またはdestroy_all
を使えます。
# Davidという名前のユーザーを検索してすべて削除 User.destroy_by(name: 'David') # 全ユーザーを削除 User.destroy_all
Active Recordを使って、モデルがデータベースに書き込まれる前にモデルの状態をバリデーション(検証: validation)できます。Active Recordにはモデルチェック用のさまざまなメソッドが用意されており、属性が空でないかどうか、属性が一意かどうか、既にデータベースにないかどうか、特定のフォーマットに沿っているかどうか、多岐にわたったバリデーションが行えます。
バリデーションは、データベースを永続化するときに考慮すべき重要な課題です。そのため、save
、update
メソッドは、バリデーションに失敗するとfalse
を返します。このとき実際のデータベース操作は行われません。上のメソッドにはそれぞれ破壊的なバージョン (save!
、update!
) があり、こちらは検証に失敗した場合にさらに厳しい対応、つまりActiveRecord::RecordInvalid
例外を発生します。以下はバリデーションの簡単な例です。
class User < ApplicationRecord validates :name, presence: true end
irb> user = User.new irb> user.save => false irb> user.save! ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
バリデーションについて詳しくは、Active Record バリデーションガイドを参照してください。
Active Recordコールバックを使うと、モデルのライフサイクル内で特定のイベントにコードをアタッチして実行できます。これにより、モデルで特定のイベントが発生したときにコードを透過的に実行できます。レコードの作成、更新、削除などさまざまなイベントに対してコールバックを設定できます。コールバックについて詳しくは、Active Recordコールバックガイドを参照してください。
Railsにはデータベーススキーマを管理するためのDSL(ドメイン固有言語: Domain Specific Language)があり、マイグレーション(migration)と呼ばれています。マイグレーションをファイルに保存してbin/rails
を実行すると、Active Recordがサポートするデータベースに対してマイグレーションが実行されます。以下はテーブルを作成するマイグレーションです。
class CreatePublications < ActiveRecord::Migration[7.0] def change create_table :publications do |t| t.string :title t.text :description t.references :publication_type t.references :publisher, polymorphic: true t.boolean :single_issue t.timestamps end end end
Railsはどのマイグレーションファイルがデータベースにコミットされたかを把握しており、その情報を元にロールバック機能を提供しています。テーブルを実際に作成するにはbin/rails db:migrate
を実行します。ロールバックするにはbin/rails db:rollback
を実行します。
上のマイグレーションコードは特定のデータベースに依存していないことにご注目ください。MySQL、PostgreSQL、Oracleなどさまざまなデータベースに対してマイグレーションを実行できます。マイグレーションについて詳しくは、Active Recordマイグレーションを参照してください。
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。