[deploy] Setup User Elasticsearch Doc Syncing (#7049)
* sync related Elasticsearch docs when a user is updated * check for changes in all user nested keys * put user fields into a constant for easy access
This commit is contained in:
parent
2f57952a1a
commit
44d0be9c76
6 changed files with 93 additions and 0 deletions
|
|
@ -22,4 +22,8 @@ module Searchable
|
|||
def elasticsearch_doc
|
||||
self.class::SEARCH_CLASS.find_document(search_id)
|
||||
end
|
||||
|
||||
def sync_related_elasticsearch_docs
|
||||
self.class::DATA_SYNC_CLASS.new(self, saved_changes).sync_documents
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ class PodcastEpisode < ApplicationRecord
|
|||
scope :reachable, -> { where(reachable: true) }
|
||||
scope :published, -> { joins(:podcast).where(podcasts: { published: true }) }
|
||||
scope :available, -> { reachable.published }
|
||||
scope :for_user, lambda { |user|
|
||||
joins(:podcast).where(podcasts: { creator_id: user.id })
|
||||
}
|
||||
|
||||
algoliasearch per_environment: true do
|
||||
attribute :id
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class User < ApplicationRecord
|
|||
|
||||
SEARCH_SERIALIZER = Search::UserSerializer
|
||||
SEARCH_CLASS = Search::User
|
||||
DATA_SYNC_CLASS = DataSync::Elasticsearch::User
|
||||
|
||||
acts_as_followable
|
||||
acts_as_follower
|
||||
|
|
@ -199,6 +200,7 @@ class User < ApplicationRecord
|
|||
|
||||
after_create_commit :send_welcome_notification, :estimate_default_language
|
||||
after_commit :index_to_elasticsearch, on: %i[create update]
|
||||
after_commit :sync_related_elasticsearch_docs, on: %i[create update]
|
||||
after_commit :remove_from_elasticsearch, on: [:destroy]
|
||||
|
||||
algoliasearch per_environment: true, enqueue: :trigger_delayed_index do
|
||||
|
|
|
|||
51
app/services/data_sync/elasticsearch/user.rb
Normal file
51
app/services/data_sync/elasticsearch/user.rb
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
module DataSync
|
||||
module Elasticsearch
|
||||
class User
|
||||
RELATED_DOCS = %i[
|
||||
articles
|
||||
reactions
|
||||
podcast_episodes
|
||||
chat_channel_memberships
|
||||
comments
|
||||
].freeze
|
||||
|
||||
SHARED_USER_FIELDS = %i[
|
||||
username
|
||||
name
|
||||
pro
|
||||
profile_image_url
|
||||
].freeze
|
||||
|
||||
attr_accessor :user, :updated_fields
|
||||
|
||||
delegate :articles, :chat_channel_memberships, :comments, to: :@user
|
||||
|
||||
def initialize(user, updated_fields)
|
||||
@user = user
|
||||
@updated_fields = updated_fields.deep_symbolize_keys
|
||||
end
|
||||
|
||||
def sync_documents
|
||||
return unless sync_needed?
|
||||
|
||||
RELATED_DOCS.each do |relation_name|
|
||||
send(relation_name).find_each(&:index_to_elasticsearch)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sync_needed?
|
||||
updated_fields.slice(*SHARED_USER_FIELDS).any?
|
||||
end
|
||||
|
||||
def reactions
|
||||
user.reactions.readinglist
|
||||
end
|
||||
|
||||
def podcast_episodes
|
||||
PodcastEpisode.for_user(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -105,6 +105,12 @@ RSpec.describe User, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
it "on update syncs elasticsearch data" do
|
||||
allow(user).to receive(:sync_related_elasticsearch_docs)
|
||||
user.save
|
||||
expect(user).to have_received(:sync_related_elasticsearch_docs)
|
||||
end
|
||||
|
||||
it "on destroy enqueues job to delete user from elasticsearch" do
|
||||
user.save
|
||||
sidekiq_assert_enqueued_with(job: Search::RemoveFromElasticsearchIndexWorker, args: [described_class::SEARCH_CLASS.to_s, user.id]) do
|
||||
|
|
|
|||
27
spec/services/data_sync/elasticsearch/user_spec.rb
Normal file
27
spec/services/data_sync/elasticsearch/user_spec.rb
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe DataSync::Elasticsearch::User, type: :service do
|
||||
let!(:user) { create(:user) }
|
||||
|
||||
describe "#sync_documents" do
|
||||
it "reindexes RELATED_DOCS when sync is needed " do
|
||||
syncer = described_class.new(user, username: %w[name1 name2])
|
||||
described_class::RELATED_DOCS.each do |method_name|
|
||||
allow(syncer).to receive(method_name).and_call_original
|
||||
end
|
||||
syncer.sync_documents
|
||||
described_class::RELATED_DOCS.each do |method_name|
|
||||
expect(syncer).to have_received(method_name)
|
||||
end
|
||||
end
|
||||
|
||||
it "does not reindex when sync is not needed" do
|
||||
syncer = described_class.new(user, stackoverflow_url: [nil, "url"])
|
||||
described_class::RELATED_DOCS.each { |method_name| allow(syncer).to receive(method_name) }
|
||||
syncer.sync_documents
|
||||
described_class::RELATED_DOCS.each do |method_name|
|
||||
expect(syncer).not_to have_received(method_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue