1

I want to show a time link mixing comments and post so I have this objects

@posts = Post::all()
@comments = Comment::all()

If I do this

@post.each ...
... end
@comments.each ...
... end

I will get first posts and after this, the comments. But I want a timeline, how i can create this?

I need to combine both object to create just one ordered list, example:

In post:

id | name | date
1 | post1 | 2015-01-01
2 | post2 | 2013-01-01

In comments:

id | name | date
1 | comment1 | 2014-01-01
2 | comment2 | 2016-01-01

if I do this post.each ... comments.each ...

the result will that:

-post1
-post2
-comment1
-comment2

But i need order by date to get

-post2
-comment1
-post1
-comment2

Thanks, and sorry for my ugly english.

Kalvin Manson
  • 59
  • 1
  • 1
  • 4
  • what is timeline and how do you want us to help you in creating it? – Andrey Deineko Nov 19 '16 at 18:28
  • I think the OP needs a single list ordered by date/time. That's what is being called a timeline. – Ed de Almeida Nov 19 '16 at 18:31
  • 1
    As a note, `Post::all()` should be `Post.all`, as method calls should be made with `.` and empty argument lists are traditionally omitted. I'd also be *very* cautious when loading the universe like this, as your posts table could contain millions of records and this code would instantly crash your application for lack of memory. Try and use pagination whenever practical. – tadman Nov 19 '16 at 18:55

2 Answers2

2

Posts and comments are different models (and different tables), so we can't write SQL to get sorted collection, with pagination etc.

Usually I use next approach when I need mixed timeline.

I have TimelineItem model with source_id, source_type and timeline_at fields.

class TimelineItem < ApplicationRecord
  belongs_to :source, polymorphic: true
end

Then I add in models logic to create timeline_item instance when needed:

has_many :timeline_items, as: :source
after_create :add_to_timeline

def add_to_timeline
  timeline_items.create timeline_at: created_at
end

Then search and output as simple as

TimelineItem.includes(:source).order(:timeline_at).each { |t| pp t.source }
mikdiet
  • 9,859
  • 8
  • 59
  • 68
0

Solution#1 You can achieve this using UNION query.

sql= 'SELECT id, name, date FROM posts UNION ALL SELECT id, name, date FROM comments ORDER BY date'
ActiveRecord::Base.connection.execute(sql)

but union query will only work when you have same column names in both tables.

Solution#2 Add ordering logic in your view.

If you are simply displaying these records on html page then let them load on page without any specific order i.e.(first posts and then comments). Write javascript code to sort DOM elements which will run after page load.

for ref: Jquery - sort DIV's by innerHTML of children

Solution#3 Refactor your DB schema and put posts and comments in same database table. Then you will be able to query on single table. Something like this,

class Text < ActiveRecord::Base
end

class Post < Text 
end

class Comment < Text
end

Query will be Text.order(:date)

Refactoring your DB schema is too much to solve this problem. Do it if it makes sense for your application.

Community
  • 1
  • 1
dnsh
  • 3,516
  • 2
  • 22
  • 47