Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify APIs for the 'autocomplete' and 'select with search' components #9958

Merged
merged 17 commits into from
Feb 21, 2025
Merged
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 75 additions & 27 deletions app/helpers/admin/taggable_content_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ module Admin::TaggableContentHelper
# Each element of the array consists of two values: the select_name and the
# ID of the organisation
def taggable_organisations_container
Rails.cache.fetch(taggable_organisations_cache_digest, expires_in: 1.day) do
Organisation.with_translations.order("organisation_translations.name").map { |o| [o.select_name, o.id] }
cached_taggable_organisations.map do |o|
[o.select_name, o.id]
end
end

Expand All @@ -16,16 +16,14 @@ def taggable_organisations_container
# role, the date the role was held if it's in the past, and the organisations
# the person belongs to) and the ID of the role appointment.
def taggable_ministerial_role_appointments_container
Rails.cache.fetch(taggable_ministerial_role_appointments_cache_digest, expires_in: 1.day) do
role_appointments_container_for(RoleAppointment.for_ministerial_roles)
cached_taggable_ministerial_role_appointments.map do |appointment|
[role_appointment_label(appointment), appointment.id]
end
end

def taggable_needs_container
Rails.cache.fetch("need.linkables", expires_in: 1.minute) do
Services.publishing_api.get_linkables(document_type: "need").to_a.map do |need|
need.values_at("title", "content_id")
end
Services.publishing_api.get_linkables(document_type: "need").to_a.map do |need|
need.values_at("title", "content_id")
end
rescue GdsApi::TimedOutException, GdsApi::HTTPServerError
stale_data = Rails.cache.fetch("need.linkables")
Expand All @@ -40,64 +38,66 @@ def taggable_needs_container
# held if it's in the past, and the organisations the person belongs to) and
# the ID of the role appointment.
def taggable_role_appointments_container
Rails.cache.fetch(taggable_role_appointments_cache_digest, expires_in: 1.day) do
role_appointments_container_for(RoleAppointment)
cached_taggable_role_appointments.map do |appointment|
[role_appointment_label(appointment), appointment.id]
end
end

# Returns an Array that represents the current set of taggable detauled
# guides. Each element of the array consists of two values: the guide title
# and its ID.
def taggable_detailed_guides_container
Rails.cache.fetch(taggable_detailed_guides_cache_digest, expires_in: 1.day) do
DetailedGuide.alphabetical.latest_edition.active.map { |d| [d.title, d.id] }
cached_taggable_detailed_guides.map do |d|
[d.title, d.id]
end
end

# Returns an Array that represents the current set of taggable statistical
# data sets. Each elements of the array consists of two values: the data
# set title and its ID.
def taggable_statistical_data_sets_container
Rails.cache.fetch(taggable_statistical_data_sets_cache_digest, expires_in: 1.day) do
StatisticalDataSet.with_translations.latest_edition.map do |data_set|
[data_set.title, data_set.document_id]
end
cached_taggable_statistical_data_sets.map do |data_set|
[data_set.title, data_set.document_id]
end
end

# Returns an Array that represents the taggable world locations. Each element
# of the array consists of two values: the location name and its ID
def taggable_world_locations_container
Rails.cache.fetch(taggable_world_locations_cache_digest, expires_in: 1.day) do
WorldLocation.ordered_by_name.where(active: true).map { |w| [w.name, w.id] }
cached_taggable_world_locations.map do |w|
[w.name, w.id]
end
end

# Returns an Array that represents the taggable roles. Each element of the
# array consists of two values: the role name and its ID
def taggable_roles_container
Rails.cache.fetch(taggable_roles_cache_digest, expires_in: 1.day) do
Role.order(:name).map { |w| [w.name, w.id] }
cached_taggable_roles.map do |w|
[w.name, w.id]
end
end

# Returns an Array that represents the taggable alternative format providers.
# Each element of the array consists of two values: the label (organisation
# and the email address if avaiable) and the ID of the organisation.
def taggable_alternative_format_providers_container
Rails.cache.fetch(taggable_alternative_format_providers_cache_digest, expires_in: 1.day) do
Organisation.alphabetical.map do |o|
["#{o.name} (#{o.alternative_format_contact_email.presence || '-'})", o.id]
end
cached_taggable_alternative_format_providers.map do |o|
["#{o.name} (#{o.alternative_format_contact_email.presence || '-'})", o.id]
end
end

# Returns an Array that represents the taggable worldwide organisations.
# Each element of the array consists of two values: the name of the worldwide
# organisation and its ID.
def taggable_worldwide_organisations_container
Rails.cache.fetch(taggable_worldwide_organisations_cache_digest, expires_in: 1.day) do
WorldwideOrganisation.with_translations.latest_edition.map { |wo| [wo.title, wo.document.id] }
cached_taggable_worldwide_organisations.map do |wo|
[wo.title, wo.document.id]
end
end

def cached_taggable_organisations
Rails.cache.fetch(taggable_organisations_cache_digest, expires_in: 1.day) do
Organisation.with_translations.order("organisation_translations.name")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these queries (this one being a good example) shouldn't really be very slow - if it is it might be a missing index on the translation name. I can very much imagine a MoG change scenario where we put an org live and then have to shell into prod to clear the cache because we can't tag any content to it.

I suppose my question is could we apply the caching a bit more selectively/check we've got the indexes we need? Probably a bit outside the scope of this PR, to be fair

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I suspected as much too. Digging into the commit history (read 0a2f1b7), it looks like some of the cached queries have a significant impact on page load times, so I didn't want to open that can of worms. Would be ripe for a revisit in a future PR though.

end
end

Expand All @@ -115,6 +115,12 @@ def taggable_organisations_cache_digest
@taggable_organisations_cache_digest ||= calculate_digest(Organisation.order(:id), "organisations")
end

def cached_taggable_ministerial_role_appointments
Rails.cache.fetch(taggable_ministerial_role_appointments_cache_digest, expires_in: 1.day) do
role_appointments_container_for(RoleAppointment.for_ministerial_roles)
end
end

# Returns an MD5 digest representing the current set of taggable ministerial
# role appointments. This will change if any role appointments are added or
# changed, and also if an occupied MinisterialRole is updated.
Expand All @@ -128,44 +134,86 @@ def taggable_ministerial_role_appointments_cache_digest
)
end

def cached_taggable_role_appointments
Rails.cache.fetch(taggable_role_appointments_cache_digest, expires_in: 1.day) do
role_appointments_container_for(RoleAppointment)
end
end

# Returns an MD5 digest representing the current set of taggable ministerial
# role appointments. This will change if any role appointments are added or
# changed, and also if an occupied Role is updated.
def taggable_role_appointments_cache_digest
@taggable_role_appointments_cache_digest ||= calculate_digest(RoleAppointment.order(:id), "role-appointments")
end

def cached_taggable_detailed_guides
Rails.cache.fetch(taggable_detailed_guides_cache_digest, expires_in: 1.day) do
DetailedGuide.alphabetical.latest_edition.active
end
end

# Returns an MD5 digest representing all the detailed guides. This wil change
# if any detailed guides are added or updated.
def taggable_detailed_guides_cache_digest
@taggable_detailed_guides_cache_digest ||= calculate_digest(Document.where(document_type: "DetailedGuide").order(:id), "detailed-guides")
end

def cached_taggable_statistical_data_sets
Rails.cache.fetch(taggable_statistical_data_sets_cache_digest, expires_in: 1.day) do
StatisticalDataSet.with_translations.latest_edition
end
end

# Returns an MD5 digest representing the taggable statistical data sets. This
# will change if any statistical data set is added or updated.
def taggable_statistical_data_sets_cache_digest
@taggable_statistical_data_sets_cache_digest ||= calculate_digest(Document.where(document_type: "StatisticalDataSet").order(:id), "statistical-data-sets")
end

def cached_taggable_world_locations
Rails.cache.fetch(taggable_world_locations_cache_digest, expires_in: 1.day) do
WorldLocation.ordered_by_name.where(active: true)
end
end

# Returns an MD5 digest representing the taggable world locations. This will
# change if any world locations are added or updated.
def taggable_world_locations_cache_digest
@taggable_world_locations_cache_digest ||= calculate_digest(WorldLocation.order(:id), "world-locations")
end

def cached_taggable_roles
Rails.cache.fetch(taggable_roles_cache_digest, expires_in: 1.day) do
Role.order(:name)
end
end

# Returns an MD5 digest representing the taggable roles. This will
# change if any world locations are added or updated.
def taggable_roles_cache_digest
@taggable_roles_cache_digest ||= calculate_digest(Role.order(:id), "roles")
end

def cached_taggable_alternative_format_providers
Rails.cache.fetch(taggable_alternative_format_providers_cache_digest, expires_in: 1.day) do
Organisation.alphabetical
end
end

# Returns an MD5 digest representing the taggable alternative format
# providers. This will change if any alternative format providers are
# changed.
def taggable_alternative_format_providers_cache_digest
@taggable_alternative_format_providers_cache_digest ||= calculate_digest(Organisation.order(:id), "alternative-format-providers")
end

def cached_taggable_worldwide_organisations
Rails.cache.fetch(taggable_worldwide_organisations_cache_digest, expires_in: 1.day) do
WorldwideOrganisation.with_translations.latest_edition
end
end

# Returns an MD5 digest representing the taggable worldwide organisations. This
# will change if any worldwide organisation is added or updated.
def taggable_worldwide_organisations_cache_digest
Expand All @@ -184,7 +232,7 @@ def role_appointments_container_for(scope)
.includes(:person)
.with_translations_for(:organisations)
.with_translations_for(:role)
.ascending_start_date.map { |appointment| [role_appointment_label(appointment), appointment.id] }
.ascending_start_date
end

def role_appointment_label(appointment)
Expand Down