Rails: 建立好友名單(續)加上好友描述
這篇文章可以視為「如何在多對多關係中,記錄額外的資訊」。其實一般想要在 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,一樣是拿上一篇的程式,多了三行程式:
attr_accessor :description
,由於 ActiveRecord 的 Class 在 mapping 到資料庫時,是直接對應到 table 的 column,但目前 users table 沒有 description 這個 column,因此我們在此給 User 這個 class 一個屬性,等一下在建立好友關係時就可以一併連好友描述都塞到 friendships 裡面。:insert_sql
,因為除了 ActiveRecord 會幫我們找到 foreign_key 所屬的欄位之外,我們還需要塞入額外的資訊,因此自訂語法。after_find
的定義,由於 ActiveRecord 撈出資料後,User 這個 model 本身沒有 description 欄位,所以我們在撈出好友關係的時候,再把 description 寫到剛剛建立好的屬性。
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},
如此一來,你就可以用下列的程式來建立、取得好友及描述
u = User.create(:name => "linyiru")
k = User.create(:name => "punk")
u.description = "Rails 愛好者: linyiru"
k.friends <<u unless k.friends.include?(u)
# 輸出好友描述
k.friends.each do |friend|
puts friend.description
end
註:description 的字串丟進去之前要記得先處理,避免發生不必要的問題,例如 SQL injection 之類的。