Posted by
這篇文章你可以視為「如何在多對多關係中,記錄額外的資訊」。其實一般想要在M:N之間的關係記錄額外的資訊,應該是會透過has_many :through比較恰當,不過因為當初我在寫好友名單時,先用了上一篇文章的寫法,所以才找到本篇文章要談的作法。
簡單來說,如果要記錄的資訊只有一個欄位,用本篇作法是快又有效;否則,我認為還是用has_many :through應該比較方便。後者的作法下次再談。
常見的社群網站,建立好友之間的關係不外乎是加入好友、並通知對方,似乎比較少有可以替好友分群組、加上描述的功能,其中丁丁大站就是可以替好友們加上描述以及分組的。這篇文章就是教你如何像丁丁大站一樣,用簡單的程式建立好友關係並加上簡單的描述。
首先一樣是你必須有一張記錄Friendship的Table,偷用上一篇的Migration(這樣上一篇瞬間變得毫無意義了-.-,不過我的想法是,一般人應該只會用到上一篇的作法。)。注意,與上一篇不同的是,這裡多了description欄位
class AddFriendship < ActiveRecord::Migration
def self.up
create_table :friendships, :id => false do |t|
t.column :user_id, :integer, :null => false
t.column :friend_id, :integer, :null => false
t.column :description :string
end
end
def self.down
drop_table :friendships
end
end
接下來一樣是定義model,一樣是拿上一篇的程式,多了三行程式:
class User < ActiveRecord::Base
attr_accessor :description
has_and_belongs_to_many :friends,
:class_name => "User",
:join_table => "friendships",
:association_foreign_key => "friend_id",
:foreign_key => "user_id",
:insert_sql => 'INSERT into friendships (user_id, friend_id, description) VALUES (#{id}, #{record.id}, \'#{record.description}\')'
# 要特別注意引號的使用,尤其description通常都是string,所以用單引號框起來
def after_find
self.description = self["description"]
# 說實在這邊我也不是很確定寫法是否正確XD應該說可以work,但不知道有沒有更好的寫法:p
end
end
如此一來,你就可以用下列的程式來建立、取得好友及描述
u = User.create(:name => "deduce") k = User.create(:name => "punk") u.description = "Rails愛好者:deduce" k.friends << u unless k.friends.include?(u) # 輸出好友描述 k.friends.each do |friend| puts friend.description end
註:description的字串丟進去之前要記得先處理,避免發生不必要的問題,例如SQL injection之類的。
其實不用定義 after_find 那一段也可以 work..
因為 has_and_belongs_to_many 會自動把 join table 除了兩個 freign key 外的欄位都加到找到的物件中。
(不過這個行為已經被 Deprecated 了 ..其實在 join table 加欄位本來就不是建議的做法..)
嗯~不定義after_find的話必須以存取hash的方式去讀資料,
也就是user["description"],我會定義那段是希望可以統一用properties存取,也就是user.description。
不過也的確如此的加欄位方式還是少用比較好:p
其實不用加也是可以直接用 properties 而不是 hash 的方式存取
ActiveRecord 的 Object 都是這樣子..
是嗎...因為我try了好幾次發現直接user.description都是nil
所以才寫了after_find來塞值..orz