DBテーブル間の結びつき その3【has_one とか has_and_belongs_to_many とか】
ケース1 テーブルAの1レコードに対してテーブルBの1レコードが対応
ケース2 テーブルAの1レコードに対してテーブルBのたくさんのレコードが対応
ケース3 テーブルAのたくさんのレコードに対してテーブルBのたくさんのレコードが対応
とあります。Rails はそれぞれをモデルファイルで指定できます。
前回のエントリの都道府県テーブルと市区町村テーブルは、上記のケース2にあたりますね。
普段のエントリに漏れず、やはり例が分かりやすいと思うので、上記の3ケースの例を書いてみます。
ケース1 都道府県 (1) -> (1) 知事
ケース2 都道府県 (1) -> (たくさん) 市区町村
ケース3 都道府県 (たくさん) <-> (たくさん) 路線
今回は、上記のケース1と、ケース3をナイスカバー(©中山律子 in ザ・スターボウリング)してみたいと思います。
まず、ケース1
前々回作った都道府県テーブルを使用します。それから、新しく知事テーブルを作ります。
知事テーブル governors
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| prefecture_id | int(11) | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
そしてそして、知事モデルを追加します。
app/models/governor.rb
class Governor < ActiveRecord::Base
belongs_to :prefecture
end
さらに、都道府県モデルに知事モデルのことを書きます。
app/models/prefecture.rb
class Prefecture < ActiveRecord::Base
has_many :cities
has_one :governor
end
じゃあ、これを書いたことで何できるの?というところですが、前回のように、belongs_to 側(知事側)から都道府県の操作をするのはつまんなーいので、都道府県側から知事側を操作します。ほいっ。
pref = Prefecture.find_by_name('東京都')
pref.create_governor(:name => '石原慎太郎', :age => 75)
pref = Prefecture.find_by_name('千葉県')
pref.create_governor(:name => '堂本暁子', :age => 75)
pref = Prefecture.find_by_name('埼玉県')
pref.create_governor(:name => '上田清司', :age => 59)
pref = Prefecture.find_by_name('神奈川県')
pref.create_governor(:name => '松沢成文', :age => 49)
石原さんが結構ご高齢なのですね。テレビでは若く見えます。
次に、ケース3
路線テーブルを作ります。
路線テーブル raillines
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| train_color | varchar(255) | YES | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
でも、この路線テーブルは、都道府県テーブルに結びつく外部キー prefecture_id を持っとらんですね、そう、このケースは中間テーブルが別に必要なのです。
都道府県-路線テーブル prefectures_raillines
(※1 アルファベット順に2つのテーブル名をつなげること!!)
(※2 auto_incrementのidカラムを作らないこと!!作ってしまうと、Mysql::Error: #23000Duplicate entry エラーがでて主キーが重なるときがある)
↑ちなみに、rake db:migrate では、:id => false を指定します
+---------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------+------+-----+---------+----------------+
| prefecture_id | int(11) | YES | | NULL | |
| railline_id | int(11) | YES | | NULL | |
+---------------+---------+------+-----+---------+----------------+
でも、この中間テーブル prefectures_raillines に対しては、モデルはいりません。
路線モデルを新規に追加、そして既存の都道府県モデルに1行書き足すだけでよろしかろう。
路線モデル
app/models/railline.rb
class Railline < ActiveRecord::Base
has_and_belongs_to_many :prefectures
end
都道府県モデル
app/models/prefecture.rb
class Prefecture < ActiveRecord::Base
has_many :cities
has_one :governor
has_and_belongs_to_many :raillines
end
以上をやりますと、都道府県に対する路線を簡単にDBに挿入できたりします。(その逆も簡単です。)
pref = Prefecture.find_by_name('東京都')
pref.raillines.create(:name => '山手線', :train_color => '緑')
pref.raillines.create(:name => '総武線', :train_color => '黄')
pref = Prefecture.find_by_name('千葉県')
rail = Railline.find_by_name('総武線')
pref.raillines.push(rail) # 千葉県と総武線を結びつける
という訳で、まだまだカバーし足りない部分(:through オプションとか・・・)もあるのですが、そちらは続編を書く気になれば書きますし、リクエストがあれば即書くと思います。(乗せられやすいから)
では、さらばー。
【広告】