Class: SidebarSiteSettingsBackfiller

Inherits:
Object
  • Object
show all
Defined in:
app/services/sidebar_site_settings_backfiller.rb

Overview

A service class that backfills the changes to the default sidebar categories and tags site settings.

When a category/tag is removed from the site settings, the ‘SidebarSectionLink` records associated with the category/tag are deleted.

When a category/tag is added to the site settings, a ‘SidebarSectionLink` record for the associated category/tag are created for all users that do not already have a `SidebarSectionLink` record for the category/tag.

Instance Method Summary collapse

Constructor Details

#initialize(setting_name, previous_value:, new_value:) ⇒ SidebarSiteSettingsBackfiller

Returns a new instance of SidebarSiteSettingsBackfiller.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'app/services/sidebar_site_settings_backfiller.rb', line 11

def initialize(setting_name, previous_value:, new_value:)
  @setting_name = setting_name

  @linkable_klass, previous_ids, new_ids =
    case setting_name
    when "default_navigation_menu_categories"
      [Category, previous_value.split("|"), new_value.split("|")]
    when "default_navigation_menu_tags"
      klass = Tag

      [
        klass,
        klass.where(name: previous_value.split("|")).pluck(:id),
        klass.where(name: new_value.split("|")).pluck(:id),
      ]
    else
      raise "Invalid setting_name"
    end

  @added_ids = new_ids - previous_ids
  @removed_ids = previous_ids - new_ids
end

Instance Method Details

#backfill!Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'app/services/sidebar_site_settings_backfiller.rb', line 34

def backfill!
  DistributedMutex.synchronize("backfill_sidebar_site_settings_#{@setting_name}") do
    SidebarSectionLink.where(
      linkable_type: @linkable_klass.to_s,
      linkable_id: @removed_ids,
    ).delete_all

    User
      .real
      .where(staged: false)
      .select(:id)
      .find_in_batches do |users|
        rows = []

        users.each do |user|
          @added_ids.each do |linkable_id|
            rows << {
              user_id: user[:id],
              linkable_type: @linkable_klass.to_s,
              linkable_id: linkable_id,
            }
          end
        end

        SidebarSectionLink.insert_all(rows) if rows.present?
      end
  end
end

#number_of_users_to_backfillObject



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'app/services/sidebar_site_settings_backfiller.rb', line 63

def number_of_users_to_backfill
  select_statements = []

  select_statements.push(<<~SQL) if @removed_ids.present?
    SELECT
      sidebar_section_links.user_id
    FROM sidebar_section_links
    WHERE sidebar_section_links.linkable_type = '#{@linkable_klass.to_s}'
    AND sidebar_section_links.linkable_id IN (#{@removed_ids.join(",")})
    SQL

  if @added_ids.present?
    # Returns the ids of users that will receive the new additions by excluding the users that already have the additions
    # Note that we want to avoid doing a left outer join against the "sidebar_section_links" table as PG will end up having
    # to do a full table join for both tables first which is less efficient and can be slow on large sites.
    select_statements.push(<<~SQL)
    SELECT
      users.id
    FROM users
    WHERE users.id NOT IN (
      SELECT
        DISTINCT(sidebar_section_links.user_id)
      FROM sidebar_section_links
      WHERE sidebar_section_links.linkable_type = '#{@linkable_klass.to_s}'
      AND sidebar_section_links.linkable_id IN (#{@added_ids.join(",")})
    ) AND users.id > 0 AND NOT users.staged
    SQL
  end

  return 0 if select_statements.blank?

  DB.query_single(<<~SQL)[0]
  SELECT
    COUNT(*)
  FROM (#{select_statements.join("\nUNION DISTINCT\n")}) AS user_ids
  SQL
end