2013-03-04 82 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