Pergunta

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

Foi útil?

Solução

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 )

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top