[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:
Molly Struve 2020-04-03 09:07:32 -05:00 committed by GitHub
parent 2f57952a1a
commit 44d0be9c76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 93 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View 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