PR

Active Recordの使い方

2010年10月13日(水)
朝倉 慎一

5. モデル間の関連とクエリー・インタフェース

Active Recordでは、モデル間の関連を定義できます。定義できるのは、1対多、1対1、多対多、多態的関連、の4種です。多態的関連とは、1つのテーブルを複数のモデルで共有する形式のことであり、STI(Single Table Instance)と呼ばれます。モデル間の関連を定義することで、関連するデータの取得や追加が、簡単にできるようになります。

モデル間に関連を持たせるには、参照元となるテーブルに、外部キーとなる列が必要です。このため、テーブル作成時に定義しておく必要があります。

以下に、例を示します。図2は、「フォーラム内に複数のトピックがある」という、1対多の関連を示しています。この場合、has_many、belongs_toを使って、関連を定義します。dependentオプションは、親レコードが削除されたときの子の削除規則を設定するものです。

図2: 1対多の関連(クリックで拡大)

関連を定義すると、関連名を使用することにより、以下のように、関連するテーブル間の操作ができるようになります。

forum = Forum.create(:title => "Rubyフォーラム") #フォーラム作成
topic = Topic.create(:subject => "Rubyトピック", :forum => forum) #上記フォーラムに属するトピックとして作成
forum = Forum.first #フォーラムを取得
topic = Topic.create(:subject => "Railsトピック") #トピックを作成
forum.topics << topic #作成したトピックをフォーラムに追加
forum = Forum.first #フォーラムを取得
topics = forum.topics #フォーラムに属するトピックを取得

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メソッド使用してデータを取得する、簡単な例です。

forum = Forum.find(1) #idが1のレコードを取得
forum = Forum.first #最初のレコードを取得
forums = Forum.all #すべてのレコードを取得

whereメソッドなどを使用して、抽出条件を設定します。find(all、first、lastを含む)以外のメソッドは、データベースにはアクセスしません。これらは、SQL文を組み立てるために必要な情報が入ったActiveRecord::Relationオブジェクトを返し、実際にデータが必要になるまでデータベースにはアクセスしない遅延ロードとなっています。以下の例では、最後の行でデータベースにアクセスして、データの取得を行います。

forum = Forum.where(:locked => false).order("created_at") #抽出条件の指定
forum = forum.joins(:topics) #テーブルの連結
topics = Topic.where("status = ?", ["published"]) #パラメータ化クエリーの例
forum_topics = forum & topics #上記条件のマージ
forum_topics.all #データの取得

また、Rubyの範囲演算子を使うとBETWEEN演算子になり、抽出条件が配列の場合はIN句を使うようになります。

forum = Forum.where(:created_at => Date.yesterday.to_time .. Time.now) #BETWEEN演算子
topics = Topic.where(:status => ["published","draft"]) #配列の場合は、IN句に変換
株式会社日立ソリューションズ

技術開発本部 Rubyセンタ所属
1973生まれ。入社後、グループウェア、Webアプリケーションサーバなどの技術サポート業務に従事。現在は、RubyおよびRuby on Railsを中心にしたビジネスを推進中。

連載バックナンバー

Think IT会員サービス無料登録受付中

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

他にもこの記事が読まれています