5. モデル間の関連とクエリー・インタフェース
Active Recordでは、モデル間の関連を定義できます。定義できるのは、1対多、1対1、多対多、多態的関連、の4種です。多態的関連とは、1つのテーブルを複数のモデルで共有する形式のことであり、STI(Single Table Instance)と呼ばれます。モデル間の関連を定義することで、関連するデータの取得や追加が、簡単にできるようになります。
モデル間に関連を持たせるには、参照元となるテーブルに、外部キーとなる列が必要です。このため、テーブル作成時に定義しておく必要があります。
以下に、例を示します。図2は、「フォーラム内に複数のトピックがある」という、1対多の関連を示しています。この場合、has_many、belongs_toを使って、関連を定義します。dependentオプションは、親レコードが削除されたときの子の削除規則を設定するものです。

|
図2: 1対多の関連(クリックで拡大) |
関連を定義すると、関連名を使用することにより、以下のように、関連するテーブル間の操作ができるようになります。
1 | forum = Forum.create( :title => "Rubyフォーラム" ) |
2 | topic = Topic.create( :subject => "Rubyトピック" , :forum => forum) |
2 | topic = Topic.create( :subject => "Railsトピック" ) |
Active Recordを使ってクラスを定義すると、テーブル・データを操作する各種メソッドが用意されます。Rails 3.0になって大きく変わった点は、データベースからデータを取得するメソッドです。以前は、データ取得を行うfindメソッドに対して、Hashを使ってさまざまな条件を設定していました。Rails 3.0からは、メソッド・チェインでクエリーを組み立てる方式になりました。主なメソッドを、表2に示します。
表2: データ取得用の主なメソッド
メソッド名 |
概要 |
find |
主キーを指定してレコードを取得。先頭レコードを取得するfirst、最終レコードを取得するlast、すべてのレコードを取得するallもあります。 |
where |
WHERE句を設定します。 |
select |
特定の列だけ取得します。selectで列を指定していない場合は、*が使用されます。 |
group |
GROUP BY句を設定します。 |
order |
ORDER BY句を設定します。 |
limit |
LIMIT句を設定します。 |
offset |
OFFSET句を設定します。 |
joins |
JOIN句を設定します。 |
includes |
関連するテーブルから必要なレコードをまとめて読むeager loadを行います。 |
lock |
悲観的ロックを行います。 |
readonly |
読み込み専用でレコードを取得します。 |
from |
データベースビューなどマップされたテーブル以外から読み込む際に使用します。 |
表2のメソッドを使用した例を、以下に示します。findメソッド使用してデータを取得する、簡単な例です。
whereメソッドなどを使用して、抽出条件を設定します。find(all、first、lastを含む)以外のメソッドは、データベースにはアクセスしません。これらは、SQL文を組み立てるために必要な情報が入ったActiveRecord::Relationオブジェクトを返し、実際にデータが必要になるまでデータベースにはアクセスしない遅延ロードとなっています。以下の例では、最後の行でデータベースにアクセスして、データの取得を行います。
1 | forum = Forum.where( :locked => false ).order( "created_at" ) |
2 | forum = forum.joins( :topics ) |
3 | topics = Topic.where( "status = ?" , [ "published" ]) |
4 | forum_topics = forum & topics |
また、Rubyの範囲演算子を使うとBETWEEN演算子になり、抽出条件が配列の場合はIN句を使うようになります。
1 | forum = Forum.where( :created_at => Date.yesterday.to_time .. Time .now) |
2 | topics = Topic.where( :status => [ "published" , "draft" ]) |