I recently had to create a timeline-like feature for the project I am working on. We have two models in the timeline right now, Event (sorted by starts_at) and Photo (sorted by created_at). They are fetched like this in our controller:

@user = User.find(params[:id])
@photos = User.photos.order('created_at ASC')
@events = User.events.order('starts_at ASC')

We can easily combine @photos and @events into one array by using the + operator, like so:

@timeline_items = (@photos + @events)

But that doesn’t give us a sorted array (actually it is still sorted, but in this case @events appears after @photos in the array). We can use the nifty .order_by(&:column) to sort this array. If we wanted both models to be sorted by their created_at columns we can do this:

@timeline_items = (@photos + @events).sort_by(&:created_at)

Unfortunately we do not sort @events by created_at. What we can do is create an artificial attribute on each column, which I will call timeline_order_column:

# Photos
def timeline_order_column
  created_at
end

# Events 
def timeline_order_column
  starts_at
end

And finally we sort them like we wanted to:

@timeline_items = (@photos + @events).sort_by(&:timeline_order_column)
Advertisements