ja ja ja en ja en ja zh ja en ja ja ja ja en ja en ja en ja ja ja ja ja en ja en ja ja ja en ja en ja ja zh ja ja en ja en ja en ja en ja ja ja ja ja en ja ja ja ja ja ja en nl ja de ja ja en ja ja en ja ja ru ja ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja cv es es ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja
create_table :people do |t| t.column :type, :string # 全てのモデルに共通の列 t.string :name t.string :email # Customerモデル専用列 t.decimal :balance # Employeeモデル専用列 t.integer :reports_to t.integer :dept end
class Person < ActiveRecord::Base # ... end class Customer < Person # ... end class Employee < Person # ... end class Manager < Employee # ... end
こうすると、それぞれのモデルをDBに保存するときに、railsが自動でtype列を入力してくれます。そして下記のようにfindを使うと、railsが自動でtype列を参照して、type列に対応するクラスとして取得してくれます。
Manager.create(:name => "manager") manager = Person.find_by_name("manager") p manager.class #=> Manager
これは利用頻度が結構ありそうだし、モデルをスマートに管理できそうなので覚えておこうっと。
type列を設定する時に気をつけること
単一テーブル継承でテーブルの列名に使われている「type」は、Rubyの組み込みのメソッド(.classの別名)なので下記のように使うとおかしいことになるみたい。
person.type = "Manager"
type列を設定するときは、下記のようにハッシュ形式で設定してあげるといいみたいです。
person[:type] = "Manager"
ポリモーフィックアソシエーション
単一テーブル継承は、各モデルで共通する列がある程度あれば使えるけど、共通する列が少ないときは使いにくい。そういうときにはポリモーフィックアソシエーションを使うといいらしい。(2008/7/14追記と修正を行いました)
「catalog_entryにはarticle, sound, imageのいずれか一つのコンテンツが含まれる」といった場合に、それらをまとめるresourceという仮の抽象モデル(のようなもの)を定義してポリモーフィックアソシエーションを設定してあげるとスマートに書ける。具体的には下記のようにする。
まず、テーブルに抽象モデルの外部キーとタイプを設定する。
create_table :catalog_entries do |t| t.string :name t.datetime :acquired_at t.integer resource_id t.string resource_type end
次に、各々のモデルのテーブル定義をする。
create_table :articles do |t| t.column :content, :text end create_table :sounds do |t| t.column :content, :binary end create_table :images do |t| t.column :content, :binary end
そして、各々のモデルには下記のように書いてあげる。
class CatalogEntry   true end class Article   :resource end class Sound   :resource end class Image   :resource end
このようにすると、catalogentry.resouceにArticle, Sound, Imageを設定したときに、railsが自動的にresource_idとresource_typeを入れてくれる。取得時にもrailsがresource_typeを見て、適切なモデルオブジェクトとして取得してくれる。
a = Article.new(:content => "hoge") c = CatalogEntry.new(:name = "entry", :acquired_at => Time.now) c.resource = a c.save! p c.resource_type #=> "Article"
ActiveRecord復習 - おもしろWEBサービス開発日記
ActiveRecord復習その2 - おもしろWEBサービス開発日記
RailsによるアジャイルWebアプリケーション開発 第2版
作者: Dave Thomas,David Heinemeier Hansson,Leon Breedt,Mike Clark,Andreas Schwarz,James Duncan Davidson,Justin Gehtland,前田修吾
出版社/メーカー: オーム社
発売日: 2007/10/26
購入: 18人 クリック: 300回
この商品を含むブログ (138件) を見る
*1:has_oneやbelongs_toでもできるみたい
willnet 2008-05-02 14:33
我々はConcernsとどう向き合うか
この文章は先日開催された大阪Ruby会議02での登壇内容Concerns …
Rails 3.1 の migration の変更点について
またまたRails 3.1 ネタです。Rails 3.1 では migration ファイ…
Chapter 17 Extending RSpec その2
Cahpter 17 Extending RSpec その1 - おもしろWEBサービス開発…
Rails 3.0 リリースノート和訳 - 後編
お待たせしました。後編です。一週間で書くつもりが一ヶ月かか…
countよりもcount_by_sqlの方がいいかも
前書いた書きかけのメモを発見したので加筆して載せてみます。…
« emacsでlispの勉強するときのコマンドにつ… kwoutのfirefox用アドオンリリース! »
id:willnet はてなブログPro
べんりで楽しいwebサービスをたくさん作りたい
読者です 読者をやめる 読者になる 読者になる
@netwillnetをフォロー
失敗したテストのログだけを出力するぞ
iCARE Dev Meetup #34で登壇しました
`Thread.current[:hoge]`はスレッドローカル変数を参照していると思いきや実際はファイバーローカル変数だった