diff --git a/app/controllers/sponsors_controller.rb b/app/controllers/sponsors_controller.rb index 40cd41b1c..6452091b6 100644 --- a/app/controllers/sponsors_controller.rb +++ b/app/controllers/sponsors_controller.rb @@ -1,5 +1,13 @@ class SponsorsController < ApplicationController def index - @sponsor_levels = Sponsor.active.group_by(&:level) + # v1: bump when the sponsors view or partials change, otherwise a deploy + # keeps serving the cached body until the next sponsor save. + key = "sponsors/index/v1/#{Sponsor.active.maximum(:updated_at)&.to_fs(:usec)}" + body = Rails.cache.fetch(key) do + @sponsor_levels = Sponsor.active.group_by(&:level) + render_to_string(layout: false) + end + # body is markup rendered by this app's own template, not user input + render html: body.html_safe # rubocop:disable Rails/OutputSafety end end diff --git a/spec/requests/sponsors_spec.rb b/spec/requests/sponsors_spec.rb new file mode 100644 index 000000000..6e8a75bec --- /dev/null +++ b/spec/requests/sponsors_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Sponsors' do + let!(:sponsor) { Fabricate.create(:sponsor, name: 'Acme Corp') } + + around do |example| + original_cache = Rails.cache + Rails.cache = ActiveSupport::Cache::MemoryStore.new + example.run + Rails.cache = original_cache + end + + it 'renders the sponsors page' do + get '/sponsors' + + expect(response).to have_http_status(:ok) + expect(response.body).to include('Acme Corp') + end + + it 'serves the cached body when no sponsor has been updated' do + get '/sponsors' + + # update_columns bypasses callbacks, so updated_at (and the cache key) stays unchanged + sponsor.update_columns(name: 'Renamed Corp') + + get '/sponsors' + + expect(response.body).to include('Acme Corp') + expect(response.body).not_to include('Renamed Corp') + end + + it 're-renders when a sponsor is updated' do + get '/sponsors' + + sponsor.update!(name: 'Renamed Corp') + + get '/sponsors' + + expect(response.body).to include('Renamed Corp') + end +end