안녕하세요, 저는 활성 레코드를 처음 사용했습니다. 여기에이 두 가지 맵 기능이 있으며 아래 쿼리를 만드는 데 더 나은 / 더 성능이 좋은 방법이 있는지 궁금합니다.
현재 쿼리를 실행할 때 터미널에 수백 개의 줄이 표시되고 많은 사람들이 동시에 이러한 수렴을로드하면 많은 메모리가 필요할 수 있습니다.
1 단계 는 모든 관련 대화를 얻는 것입니다.
2 단계 는 해당 대화에 연결된 발신자, 수신자 및 메시지에 대한 모든 정보로 대화 해시를 만드는 것입니다.
3 단계 는 이러한 모든 대화를 올바른 순서로 정렬하여 가장 최근 메시지가 맨 위에있는 대화에서 정렬합니다.
편집 1 : Rails 버전 5.0.1
def index
i = 1
@messages = []
@user = User.find_by(email: params[:email])
@message = Conversation.where("sender_id = ? OR recipient_id = ?", @user.id, @user.id)
@message.map { |conversation|
@messages << conversation if Message.where(conversation_id: conversation.id).count > 0
}
render json: @messages.map { |conversation|
{
date: conversation.messages.last.created_at,
sender: User.find(conversation.sender_id),
recipient: User.find(conversation.recipient_id),
conversation: {
id: conversation.id,
messages: Message.where(conversation_id: conversation.id).sort_by{|e| e[:created_at]}.reverse.map {|message| {
sender: {
email: User.find(message.user_id).email,
first_name: User.find(message.user_id).first_name,
last_name: User.find(message.user_id).last_nam },
body: message.body,
created_at: message.created_at
}
}
}}
}.sort_by { |hsh| hsh[:date] }.reverse
end
class Message < ApplicationRecord
belongs_to :conversation, touch: true
end
class Conversation < ApplicationRecord
has_many :messages, -> { order(created_at: :desc) }
belongs_to :sender, foreign_key: :sender_id, class_name: 'User'
belongs_to :recipient, foreign_key: :recipient_id, class_name: 'User'
end
class User < ApplicationRecord
has_many :conversations, -> (user) { unscope(where: :user_id).where('conversations.sender_id = ? OR conversations.recipient_id = ?', user.id, user.id) }
end
class ConversationsController < ApplicationController
def index
@user = User.find_by(email: params[:email])
# "joins(:messages)" allows only retrieving conversations having at least one message, and does not include conversation with 0 message
# now ordering by `updated_at: :asc` because `Message belongs_to :conversation, touch: true`, in which Conversation's updated_at will be automatically "touched"/updated whenever the associated Messages are updated/created.
@conversations = @user.conversations.joins(:messages).order(updated_at: :asc).distinct
json_response = @conversations.as_json(
only: [:id, :updated_at],
include: {
sender: {
only: [:id, :first_name, :last_name, :email]
},
recipient: {
only: [:id, :first_name, :last_name, :email]
},
messages: {
only: [:body, :created_at]
}
}
)
render json: json_response
end
end
예제 요청
Started GET "/conversations?email=foobar@example.com"
예제 응답
[{
"id": 2,
"updated_at": "2018-02-02T11:17:45.376Z",
"sender": {
"id": 4,
"first_name": "Lorem",
"last_name": "Ipsum",
"email": "loremipsum@example.com"
},
"recipient": {
"id": 1,
"first_name": "Foo",
"last_name": "Bar",
"email": "foobar@example.com"
},
"messages": [{
"body": "Hello there",
"created_at": "2018-02-02T11:17:45.367Z"
}, {
"body": "Whatcha doin'?",
"created_at": "2018-02-02T11:17:36.451Z"
}, {
"body": "hahaha :)",
"created_at": "2018-02-02T11:03:29.843Z"
}]
}, {
"id": 1,
"updated_at": "2018-02-02T11:36:14.275Z",
"sender": {
"id": 1,
"first_name": "Foo",
"last_name": "Bar",
"email": "foobar@example.com"
},
"recipient": {
"id": 5,
"first_name": "Ruby",
"last_name": "Rails",
"email": "rubyonrails@example.com"
},
"messages": [{
"body": "hello Ruby-on-Rails! :)",
"created_at": "2018-02-02T11:36:14.267Z"
}]
}]
.as_json
여기
touch : true
사용 방법은 여기 에서 확인할 수 있습니다.
작동 테스트