Skip to content

Instantly share code, notes, and snippets.

@absk1317
Last active August 20, 2020 09:03
Show Gist options
  • Save absk1317/5f8f78ff435bd823bf644e0bea080125 to your computer and use it in GitHub Desktop.
Save absk1317/5f8f78ff435bd823bf644e0bea080125 to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
class BaseObserver < ActiveRecord::Observer
def create?(resource)
resource.send(:transaction_include_any_action?, [:create])
end
def deleted?(resource)
resource.send(:transaction_include_any_action?, [:destroy])
end
end
class LikeObserver < BaseObserver
def after_commit(like)
commit_actions(like.id)
return unless create?(like)
create_actions(like.id)
end
def commit_actions(like_id)
AsyncWorker.perform_in(1.minutes, like_id, :update_indices)
end
def create_actions(like_id)
## to avoid false likes, ie. likes that users create by mistake
AsyncWorker.perform_in(5.seconds, like_id, :create_notification)
end
class AsyncWorker
include Sidekiq::Worker
# retry false, at times users unlike the entity just as they like, and object is deleted in that case
# and this job keeps failing. This will prevent that.
sidekiq_options retry: false
attr_accessor :like
def perform(id, method_name)
@like = Like.find_by(id: id)
return unless like
send(method_name)
end
def create_notification
notification = Notification.created_today.likes.find_by(notifiable: like.likeable)
if notification
# notify only for first like per entity in the day, make rest in-app
notification.update!(notifier: like.user,
key: "#{like.likeable.likes.created_today.count}_like",
notification_type: 'in_app')
else
Notification.create!(notifier: like.user,
key: 'like',
target: like.likeable.user,
notifiable: like.likeable)
end
end
def update_indices
return unless %w[Class1 Class2].include?(like.likeable_type)
like.likeable.reindex
end
end
end
## specs
require 'rails_helper'
describe Like, type: :model do
include RequestSpecHelper
describe 'Associations' do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:likeable) }
it { is_expected.to have_many(:notifications) }
it { is_expected.to validate_inclusion_of(:likeable_type).in_array(Like::LIKEABLES.values.map(&:name)) }
end
describe 'Callbacks' do
let!(:like) { create(:like, likeable: create(:post), user: create(:user)) }
it 'adds a notification' do
Sidekiq::Testing.inline!
expect { like.run_callbacks(:commit) }.to change { Notification.count }.by(1)
expect(strip_html(Notification.last.content)).to include('liked your post')
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment