我需要在我发送的消息和从某人收到的消息之间建立联盟。
这是我在控制器中尝试做的第一件事,但是没有订购消息。我想我需要做一个真正的联盟?
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
这是我的用户模型:
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
答案 0 :(得分:5)
在结果上使用+
时,您的消息首先加载到内存中的数组中,然后连接这些数组。所以为了节省订购,你应该再次排序。丑陋......当历史变得很大时,它会非常缓慢。
您可以使用真正的UNION,但它需要大量原始sql(通过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])
还有另一种(在我看来,稍微更优雅)使用IN操作的解决方案(仅当您的用户无法向自己发送消息时才会起作用):
@messages = Message.where(:sender_id => [current_user.id, params[:sender_id]], :recipient_id => [current_user.id, params[:sender_id])
在这两种解决方案中,您通常可以使用排序或分页。
答案 1 :(得分:1)
如果您不必使用活动记录,您可能会这样做。
这意味着,你不需要额外的条件。
@message = @message1.to_set + @message2.to_set
或
@message = @message1.to_a + @message2.to_a
但如果您确实需要将结果用作活动记录,则可能会牺牲这样的性能。
messages_set = @message1.map { |m| m.id }.to_set + @message2.map { |m| m.id }.to_set
@message = Message.where(:id => messages_set.to_a)