在物件表格映射一對一關聯上,Rails提供了has_one與belongs_to兩個方法。如果有Some、Other兩個物件,若說Some擁有一個Other,可以如下定義:
class Some < ActiveRecord::Base
has_one :other
end
則此時others表格中要有個some_id欄位作為外部鍵,參考至somes表格中的id主鍵。如果說Some屬於Other,可以如下定義:
class Some < ActiveRecord::Base
belongs_to :other
end
則此時somes表格中要有個other_id欄位作為外部鍵,參考至others表格中的id主鍵。
技術上看來,使用has_one或belongs_to,主要在於外部鍵是放在哪個表格中,實際上還是要依語意而定,例如使用者與房間的關係,可以說使用者擁有一個房間,也可以說房間屬於某個使用者,但若說使用者屬於某個房間,或房間擁有某個使用者,語意上不免奇怪。
假設想要設計的是,使用者擁有一個房間。例如:
# app/models/user.rb
class User < ActiveRecord::Base
has_one :room
end
# app/models/room.rb
class Room < ActiveRecord::Base
end
那麼可如下建立表格:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.integer :age
t.timestamps
end
end
end
class CreateRooms < ActiveRecord::Migration
def change
create_table :rooms do |t|
t.string :address
t.integer :user_id # 外鍵
t.timestamps
end
end
end
User物件有個room屬性參考至Room實例,一個儲存的例子如下所示,只要儲存User,所參考的Room也會一併儲存:
u = User.new(:name => "Justin", :age => 35)
r = Room.new(:address => "NTU-M8-419")
u.room = r
u.save
由於是由User參考了Room實例,所以儲存時使用User實例的save方法,如果使用的是Room來儲存,由於Room並沒有參考至User,就只會儲存Room而不會儲存User。
如果想設計的是,房間屬於某個使用者:
# app/models/user.rb
class User < ActiveRecord::Base
end
# app/models/room.rb
class Room < ActiveRecord::Base
belongs_to :user
end
Room物件有個user屬性會參考至User實例,儲存時要使用Room的save方法:
u = User.new(:name => "Justin", :age => 35)
r = Room.new(:address => "NTU-M8-419", :user => u)
r.save
以上兩個例子,實際上都必須先儲存User的資料,才能根據users中的id設置rooms中的user_id,也就是都使用以下的SQL:
INSERT INTO "users" ("age", "created_at", "name", "updated_at") VALUES (?, ?, ?, ?)
INSERT INTO "rooms" ("address", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?)
u.room # 此時才會從rooms表格中SELECT