Merge pull request #1040 from Retrospring/fix/n+1-notification-type-counters

Prevent 𝑛+1 for notification type counters
This commit is contained in:
Karina Kwiatek 2023-02-02 12:09:06 +01:00 committed by GitHub
commit c40a1a4997
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 9 deletions

View File

@ -16,8 +16,8 @@ class NotificationsController < ApplicationController
def index def index
@type = TYPE_MAPPINGS[params[:type]] || params[:type] @type = TYPE_MAPPINGS[params[:type]] || params[:type]
@notifications = cursored_notifications_for(type: @type, last_id: params[:last_id]) @notifications = cursored_notifications_for(type: @type, last_id: params[:last_id])
@notifications_last_id = @notifications.map(&:id).min paginate_notifications
@more_data_available = !cursored_notifications_for(type: @type, last_id: @notifications_last_id, size: 1).count.zero? @counters = count_unread_by_type
respond_to do |format| respond_to do |format|
format.html format.html
@ -27,6 +27,17 @@ class NotificationsController < ApplicationController
private private
def paginate_notifications
@notifications_last_id = @notifications.map(&:id).min
@more_data_available = !cursored_notifications_for(type: @type, last_id: @notifications_last_id, size: 1).count.zero?
end
def count_unread_by_type
Notification.where(recipient: current_user, new: true)
.group(:target_type)
.count(:target_type)
end
def mark_notifications_as_read def mark_notifications_as_read
# using .dup to not modify @notifications -- useful in tests # using .dup to not modify @notifications -- useful in tests
@notifications&.dup&.update_all(new: false) # rubocop:disable Rails/SkipsModelValidations @notifications&.dup&.update_all(new: false) # rubocop:disable Rails/SkipsModelValidations

View File

@ -11,11 +11,11 @@ class Notification < ApplicationRecord
define_cursor_paginator :cursored_for_type, :for_type define_cursor_paginator :cursored_for_type, :for_type
def for(recipient, **kwargs) def for(recipient, **kwargs)
where(kwargs.merge!(recipient:)).order(:created_at).reverse_order where(kwargs.merge!(recipient:)).includes(:target).order(:created_at).reverse_order
end end
def for_type(recipient, type, **kwargs) def for_type(recipient, type, **kwargs)
where(kwargs.merge!(recipient:)).where(type:).order(:created_at).reverse_order where(kwargs.merge!(recipient:)).includes(:target).where(type:).order(:created_at).reverse_order
end end
def notify(recipient, target) def notify(recipient, target)

View File

@ -9,18 +9,18 @@
.list-group .list-group
= list_group_item t('.answer'), = list_group_item t('.answer'),
notifications_path('answer'), notifications_path('answer'),
badge: Notification.for(current_user).where(target_type: 'Answer', new: true).count badge: @counters['Answer']
= list_group_item t('.smile'), = list_group_item t('.smile'),
notifications_path('smile'), notifications_path('smile'),
badge: Notification.for(current_user).where(target_type: 'Smile', new: true).count badge: @counters['Smile']
= list_group_item t('.comment'), = list_group_item t('.comment'),
notifications_path('comment'), notifications_path('comment'),
badge: Notification.for(current_user).where(target_type: 'Comment', new: true).count badge: @counters['Comment']
= list_group_item t('.commentsmile'), = list_group_item t('.commentsmile'),
notifications_path('commentsmile'), notifications_path('commentsmile'),
badge: Notification.for(current_user).where(target_type: 'CommentSmile', new: true).count badge: @counters['CommentSmile']
= list_group_item t('.relationship'), = list_group_item t('.relationship'),
notifications_path('relationship'), notifications_path('relationship'),
badge: Notification.for(current_user).where(target_type: 'Relationship', new: true).count badge: @counters['Relationship']
.d-none.d-sm-block= render 'shared/links' .d-none.d-sm-block= render 'shared/links'