"слияние" нескольких моделей. Чтобы создать окно "Недавняя активность"
Как объединить модели, чтобы я мог показывать последние 10 сообщений, записей фидов и личных сообщений?
Сообщения хранятся в модели "Post" и упорядочены по "created_at"
Записи фида хранятся в "Планете" и упорядочены по "published_at"
Личные сообщения хранятся в "Сообщении" и должны быть отфильтрованы с помощью:
:conditions => "receiver_id = #{current_user.id}"
и упорядочен на "created_at"
Ответы
Ответ 1
Вы должны:
- элементы запроса для каждой модели
- объединить их в общий формат
- сортировка и ограничение
Вот какой код:
class Activity < Struct.new(:title, :text, :date); end
limit = 10
activities = []
activities += Post.all(:order => 'created_at DESC', :limit => limit).map do |post|
Activity.new(post.title, post.summary, post.created_at)
end
activities += Planet.all(:order => 'published_at DESC', :limit => limit).map do |planet|
Activity.new(planet.title, planet.message, planet.published_at)
end
activities += Message.all(:conditions => ['receiver_id = ?', current_user.id], :order => 'created_at DESC', :limit => limit).map do |message|
Activity.new(message.title, message.text, message.created_at)
end
# descending sort by 'date' field
sorted_activities = activities.sort_by(&:date).reverse
# 10 most recent elements across all models
@activities = sorted_activities[0..(limit-1)]
Конечно, в зависимости от ваших моделей вам придется изменить, какой метод используется как "заголовок" или "текст".
Но если вам понадобится много таких идиом, вы должны использовать Single Table Inheritance, как в zena (рельсы CMS).
Ответ 2
Я бы использовал класс Proxy. Класс может хранить ссылку на объект ActiveRecord и поле для сортировки.
class ActivityProxy
attr_accessor :object, :date
def initialize(object, date)
self.object = object
self.date = date
end
end
Затем вы загружаете свои объекты.
activity = []
activity += Post.all(:limit => 10, :order => "created_at DESC").map { |post| ActivityProxy.new(post, post.created_at) }
# and so on with the other objects
Наконец, вы сортируете объекты
activity.sort_by(&:field)
# => here you have the sorted objects
# and you can iterate them with
activity.each do |proxy|
proxy.object.id
# ...
end
Ответ 3
Другим способом создания фидов является создание VIEW, который объединяет два, а затем пусть у представления есть собственная модель.