From 75e5f58ae0eb35f8d83cd2359df077cb85dbdece Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Tue, 17 Mar 2026 18:45:53 +0100 Subject: [PATCH 1/2] fix: handle JSON format in render_not_found Reverts the render_not_found method to use respond_to, matching the pattern used in the exception handler. This fixes MissingTemplate errors when requests come in with JSON format (e.g., from API clients). The previous change (3eeca62d) simplified render_not_found but broke JSON responses. Now HTML requests get the proper 404 page while API requests get an empty 404 response. Adds tests for both HTML and JSON format handling. --- app/controllers/application_controller.rb | 5 ++- .../application_controller_spec.rb | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 spec/controllers/application_controller_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e11faaab7..f1b7f6656 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -30,7 +30,10 @@ class ApplicationController < ActionController::Base before_action :accept_terms, if: :logged_in? def render_not_found - render template: 'errors/not_found', layout: false, status: :not_found + respond_to do |format| + format.html { render template: 'errors/not_found', layout: false, status: :not_found } + format.all { head :not_found } + end end protected diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb new file mode 100644 index 000000000..2f8e24981 --- /dev/null +++ b/spec/controllers/application_controller_spec.rb @@ -0,0 +1,31 @@ +RSpec.describe ApplicationController do + describe '#render_not_found' do + controller do + def index + raise ActiveRecord::RecordNotFound + end + end + + context 'with HTML format' do + before do + get :index, format: :html + end + + it 'renders the not_found template' do + expect(response.status).to eq(404) + expect(response).not_to be_redirect + end + end + + context 'with JSON format' do + before do + get :index, format: :json + end + + it 'returns empty 404 response' do + expect(response.status).to eq(404) + expect(response.body).to be_empty + end + end + end +end From df1d5a22e44473daf3fc9023ea21eb53c577918a Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Tue, 17 Mar 2026 18:57:53 +0100 Subject: [PATCH 2/2] fix: wrap flaky listable tests in Timecop --- spec/models/concerns/listable_spec.rb | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/spec/models/concerns/listable_spec.rb b/spec/models/concerns/listable_spec.rb index 6a8efe2b8..9040f6f31 100644 --- a/spec/models/concerns/listable_spec.rb +++ b/spec/models/concerns/listable_spec.rb @@ -2,7 +2,7 @@ subject(:workshop) { Fabricate(:workshop) } context 'scopes' do - context '#today_and_upcoming' do + describe '#today_and_upcoming' do it 'returns a list of all today and upcoming workshops' do Timecop.travel(Time.now.utc) do Fabricate.times(2, :past_workshop) @@ -26,12 +26,14 @@ end end - context '#upcoming' do + describe '#upcoming' do it 'returns a list of all upcoming workshops' do - Fabricate.times(2, :past_workshop) - future_workshops = Fabricate.times(1, :workshop) + Timecop.travel(Time.now.utc) do + Fabricate.times(2, :past_workshop) + future_workshops = Fabricate.times(1, :workshop) - expect(Workshop.upcoming).to match_array(future_workshops) + expect(Workshop.upcoming).to match_array(future_workshops) + end end it 'returns workshops ordered by date_and_time ascending (soonest first)' do @@ -44,16 +46,18 @@ end end - context '#past' do + describe '#past' do it 'returns a list of all upcoming workshops' do - past_workshops = Fabricate.times(2, :past_workshop) - Fabricate.times(1, :workshop) + Timecop.travel(Time.now.utc) do + past_workshops = Fabricate.times(2, :past_workshop) + Fabricate.times(1, :workshop) - expect(Workshop.past).to match_array(past_workshops) + expect(Workshop.past).to match_array(past_workshops) + end end end - context '#recent' do + describe '#recent' do it 'returns a list of the last 10 workshops' do Fabricate.times(1, :past_workshop) Fabricate.times(2, :workshop) @@ -65,7 +69,7 @@ end end - context '#completed_since_yesterday' do + describe '#completed_since_yesterday' do it 'returns a list of yesterday\'s events' do Fabricate(:workshop, date_and_time: 24.hours.ago) Fabricate(:workshop, date_and_time: 25.hours.ago) @@ -78,7 +82,7 @@ end end - context '#next' do + describe '#next' do it 'returns the next workshop to take place' do next_workshop = Fabricate(:workshop, date_and_time: Time.zone.now + 24.hours) Fabricate(:workshop, date_and_time: Time.zone.now + 29.hours)