2013-03-04 83 views
3

我想要每個用戶發送的最新消息。下面是樣本數據ActiveRecord - 從每個組中選擇第一條記錄

表:對話

sender receiver message      date 
============================================================ 
    1 2 "hi"       "2013-03-04 09:55:01.122074" 
    2 1 "hello"       "2013-03-04 09:55:32.903975" 
    1 2 "have you done with the taks?" "2013-03-04 09:57:46.383007" 
    2 1 "almost..."      "2013-03-04 09:58:55.783219" 
    2 1 "should be able to finish 2day" "2013-03-04 09:59:28.950705" 
    2 3 "shall we start?"    "2013-03-04 10:01:16.842725" 
    3 2 "give me a minute"    "2013-03-04 10:01:41.994589" 
    3 2 "let us start"     "2013-03-04 10:02:14.04551" 

凡ID爲2的用戶,我應該能夠得到以下兩個記錄

1 2 "have you done with the taks?" "2013-03-04 09:57:46.383007"   
3 2 "let us start"     "2013-03-04 10:02:14.04551" 

這裏是我的解決方案

型號:用戶

class User < ActiveRecord::Base 
has_many :chats_received, class_name: 'Conversation', foreign_key: 'receiver_id',order: "created_at DESC" 
end 

型號:會話

class Conversation < ActiveRecord::Base 
    attr_accessible :message, :read 

    belongs_to :sender, class_name: 'User' 
    belongs_to :receiver, class_name: 'User' 

    def most_recent_chat_received_from_connected_users 
    connected_users_chats = . . . # Get all conversations which are sent to current user. e.g., user with id 2 
    chats_grouped_by_senders = connected_users_chats.group_by { |conversation| conversation.sender_id } 
    chats_grouped_by_senders.inject([]){|memo , (sender_id, conversations)| memo << conversations.first; memo} 
    end 
end 

獲取最新的連接用戶信息:

user = User.find 2 
user.most_recent_chat_received_from_connected_users 

雖然此解決方案有效,它選擇和兩個轉換之間創建模型用戶。另外我覺得這不是獲得所需行數的軌道方式。

我一直在使用postgresql。當我嘗試在模式中使用組方法時,我一直在收到以下錯誤。

ActiveRecord::StatementInvalid: PG::Error: ERROR: column "conversations.id" must appear in the GROUP BY clause or be used in an aggregate function 

有沒有更好的方法來獲得相同的結果?

回答

6

我不知道你能怎麼稱呼most_recent_chat_received_from_connected_users,這是你的Conversation類的實例方法,對User實例沒有得到一個錯誤,但我會一個定製的查找添加到會話模型:

class Conversation < ActiveRecord::Base 
    # ... 

    def self.most_recent_for(user_id) 
    select('DISTINCT ON (sender_id) *').where(reciever_id: user_id).order("sender_id, created_at DESC") 
    end 

    # For MySQL you could have used: 
    # 
    # def self.most_recent_for(user_id) 
    # where(reciever_id: user_id).group("sender_id").order("created_at DESC") 
    # end 

    # ... 
end 

現在你可以在你的控制器所需的交談:

@conversations = Conversation.most_recent_for(current_user.id) 
+0

收到此錯誤'''的ActiveRecord :: StatementInvalid:PG ::錯誤:錯誤:列 「conversations.id」 必須出現在GROUP BY子句或b e在彙總函數中使用 – 2013-03-05 06:14:56

+0

仔細閱讀,但測試不佳(使用MySQL)。答案已更新! – mattbjom 2013-03-05 08:37:08

+0

很酷。有效。 – 2013-03-05 09:17:18