6
Oct

前言

這篇文章你可以視為「如何在多對多關係中,記錄額外的資訊」。其實一般想要在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}, \'#{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之類的。

References

Category : Ruby on Rails學習筆記

4 Responses to “Rails: 建立好友名單(續)加上好友描述”


contagion October 8, 2007

其實不用定義 after_find 那一段也可以 work..
因為 has_and_belongs_to_many 會自動把 join table 除了兩個 freign key 外的欄位都加到找到的物件中。
(不過這個行為已經被 Deprecated 了 ..其實在 join table 加欄位本來就不是建議的做法..)

deduce October 9, 2007

嗯~不定義after_find的話必須以存取hash的方式去讀資料,
也就是user["description"],我會定義那段是希望可以統一用properties存取,也就是user.description。

不過也的確如此的加欄位方式還是少用比較好:p

contagion October 10, 2007

其實不用加也是可以直接用 properties 而不是 hash 的方式存取
ActiveRecord 的 Object 都是這樣子..

deduce October 10, 2007

是嗎...因為我try了好幾次發現直接user.description都是nil
所以才寫了after_find來塞值..orz



Spam protection by WP Captcha-Free