两个ActiveRecord :: Relations之间的联合

Med*_*max 2 activerecord ruby-on-rails ruby-on-rails-3.2

我需要在我发送的消息和从某人收到的消息之间建立联盟.

这是我在控制器中尝试做的第一件事,但是没有订购消息.我想我需要做一个真正的联盟?

def listmessages
   @messages1 = current_user.messages.where(:sender_id => params[:sender_id])
   @messages2 = current_user.sent_messages.where(:recipient_id => params[:sender_id])
   @messages = @messages1 + @messages2
end
Run Code Online (Sandbox Code Playgroud)

这是我的用户模型:

class User < ActiveRecord::Base
   before_create :distribute_points

   devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable, :confirmable

   has_many :sent_messages, foreign_key: "sender_id", class_name:"Message",
       order: "created_at DESC"

   has_many :messages, foreign_key: "recipient_id", order: "created_at DESC"
end
Run Code Online (Sandbox Code Playgroud)

aln*_*lno 5

当您使用+结果时,您的消息首先加载到内存中的数组中,然后连接这些数组.所以为了节省订购,你应该再次排序.丑陋......当历史变得很大时非常缓慢.

您可以使用真正的UNION,但它需要大量的原始sql(through Message.find_by_sql("your union query")),这非常难看且难以维护.

在你的情况下,使用OR代替UNION可能更好:

@messages = Message.where('(sender_id = ? AND recipient_id = ?) OR (recipient_id = ? AND sender_id = ?)', current_user.id, params[:sender_id], current_user.id, params[:sender_id])
Run Code Online (Sandbox Code Playgroud)

还有另一种(在我看来,稍微更优雅)使用IN操作的解决方案(仅当您的用户无法向自己发送消息时才会起作用):

@messages = Message.where(:sender_id => [current_user.id, params[:sender_id]], :recipient_id => [current_user.id, params[:sender_id])
Run Code Online (Sandbox Code Playgroud)

在这两种解决方案中,您通常可以使用排序或分页.