Question

I have a Notification model:

Notification(id: integer, notifiable_id: integer, notifiable_type: string, user_id: integer, created_at: datetime, updated_at: datetime)

notifications controller:

def index
  @notifications = current_user.notifications.page(params[:page]).per(10)
end

In view it displays records as:

user1 commented on post1
user2 commented on post1
user3 subscribed to blog1
user4 subscribed to blog1

How can I group by notifiable to display instead:

user1, user2 commented on post1
user3, user4 subscribed to blog1

Was it helpful?

Solution

The response will depend on the database you use.

Postgresql

For postgres, you can do something like this :

@notifications = current_user.notifications.
                 select( "string_agg( users.user_name, ', ' ) as user_names, notifiables.name as notifiable_name" ).
                 group( 'notifiables.name, notifications.notifiable_type' ).
                 joins( :notifiable ).joins( :user ).
                 page(params[:page]).per(10)

Then, use the aggrated object like that :

@notifications.map { |n| "#{n.user_names} #{n.notifiable_type} #{n.notifable_name}" }

Note that I have guessed you other tables field names, so adapt accordingly.

The basic idea is to group your results and use database concatenation features. Kaminari and will_paginate will work happily with the result.

Beware : as always when you use #select, do not write objects back to database or they'll be corrupted.

MySql

For mysql, this should be basically the same, but replacing string_agg( users.user_name, ', ' ) with group_concat( users.user_name )

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top