summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-14 16:52:03 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-14 16:53:15 +0200
commitffb3c9987c2f820b99e8ad0ad56db8ae0324671c (patch)
tree5f8ae79e6952cc6808ba5d5f827c98b6c78b62df
parentc7ed30918154d801c44f77645ead38d4759d2778 (diff)
Extend static-asset cache-busting to the public layout
mtime_busted_path only ever covered the four admin-only static files. The public layout has the identical exposure -- ccc.css, glightbox's vendored CSS/JS, and public.js are all served straight from public/ with no pipeline fingerprinting either -- just never got the same treatment.
-rw-r--r--app/helpers/admin_helper.rb6
-rw-r--r--app/helpers/application_helper.rb14
-rw-r--r--app/views/layouts/application.html.erb8
-rw-r--r--test/models/helpers/admin_helper_test.rb10
-rw-r--r--test/models/helpers/application_helper_test.rb14
5 files changed, 32 insertions, 20 deletions
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
index 6c3cbc6..2684fff 100644
--- a/app/helpers/admin_helper.rb
+++ b/app/helpers/admin_helper.rb
@@ -7,10 +7,4 @@ module AdminHelper
7 link_to raw('<span class="inactive">Deutsch</span>'), url_for(params.permit(:locale, :page_path).to_h.merge('locale' => 'de')) 7 link_to raw('<span class="inactive">Deutsch</span>'), url_for(params.permit(:locale, :page_path).to_h.merge('locale' => 'de'))
8 end 8 end
9 end 9 end
10
11 def mtime_busted_path(path)
12 file = Rails.public_path.join(path.sub(%r{\A/}, ""))
13 raise "Static asset not found for cache-busting: #{path} (looked for #{file})" unless File.exist?(file)
14 "#{path}?v=#{File.mtime(file).to_i}"
15 end
16end 10end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 87aa82c..0d28661 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -15,4 +15,18 @@ module ApplicationHelper
15 def resolve_kind_text(value) 15 def resolve_kind_text(value)
16 value.respond_to?(:call) ? value.call : value 16 value.respond_to?(:call) ? value.call : value
17 end 17 end
18
19 # Cache-busts a static file living directly under public/, outside the
20 # asset pipeline -- used by both the admin and public layouts, since
21 # neither loads its static CSS/JS through Sprockets (admin_bundle.js is
22 # the one exception; it already gets pipeline fingerprinting for free).
23 # Raises rather than silently omitting the version param: a missing
24 # file here means the page is already broken, and failing loudly beats
25 # a confusing "why is the browser still showing the old version" report
26 # days later.
27 def mtime_busted_path(path)
28 file = Rails.public_path.join(path.sub(%r{\A/}, ""))
29 raise "Static asset not found for cache-busting: #{path} (looked for #{file})" unless File.exist?(file)
30 "#{path}?v=#{File.mtime(file).to_i}"
31 end
18end 32end
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 57d12e6..d7681af 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -10,10 +10,10 @@
10 <meta property="og:description" content="Der Chaos Computer Club ist eine galaktische Gemeinschaft von Lebewesen für Informationsfreiheit und Technikfolgenabschätzung." /> 10 <meta property="og:description" content="Der Chaos Computer Club ist eine galaktische Gemeinschaft von Lebewesen für Informationsfreiheit und Technikfolgenabschätzung." />
11 11
12 <title><%= page_title %></title> 12 <title><%= page_title %></title>
13 <link rel="stylesheet" href="/stylesheets/ccc.css"> 13 <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/ccc.css') %>">
14 <link rel="stylesheet" href="/stylesheets/glightbox.min.css"> 14 <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/glightbox.min.css') %>">
15 <script src="/javascripts/glightbox.min.js"></script> 15 <script src="<%= mtime_busted_path('/javascripts/glightbox.min.js') %>"></script>
16 <script src="/javascripts/public.js"></script> 16 <script src="<%= mtime_busted_path('/javascripts/public.js') %>"></script>
17 17
18 <%= auto_discovery_link_tag(:atom, '/rss/updates.xml', title: "ATOM") %> 18 <%= auto_discovery_link_tag(:atom, '/rss/updates.xml', title: "ATOM") %>
19 <%= auto_discovery_link_tag(:rss, '/rss/updates.rdf', title: "RSS") %> 19 <%= auto_discovery_link_tag(:rss, '/rss/updates.rdf', title: "RSS") %>
diff --git a/test/models/helpers/admin_helper_test.rb b/test/models/helpers/admin_helper_test.rb
index 94e9861..23d9f40 100644
--- a/test/models/helpers/admin_helper_test.rb
+++ b/test/models/helpers/admin_helper_test.rb
@@ -1,14 +1,4 @@
1require 'test_helper' 1require 'test_helper'
2 2
3class AdminHelperTest < ActionView::TestCase 3class AdminHelperTest < ActionView::TestCase
4 test "mtime_busted_path appends the file's real mtime as a query param" do
5 path = "/stylesheets/admin.css"
6 expected_mtime = File.mtime(Rails.public_path.join("stylesheets/admin.css")).to_i
7
8 assert_equal "#{path}?v=#{expected_mtime}", mtime_busted_path(path)
9 end
10
11 test "mtime_busted_path raises clearly for a missing file rather than silently omitting the version" do
12 assert_raises(RuntimeError) { mtime_busted_path("/stylesheets/does_not_exist.css") }
13 end
14end 4end
diff --git a/test/models/helpers/application_helper_test.rb b/test/models/helpers/application_helper_test.rb
new file mode 100644
index 0000000..56096a5
--- /dev/null
+++ b/test/models/helpers/application_helper_test.rb
@@ -0,0 +1,14 @@
1require 'test_helper'
2
3class ApplicationHelperTest < ActionView::TestCase
4 test "mtime_busted_path appends the file's real mtime as a query param" do
5 path = "/stylesheets/admin.css"
6 expected_mtime = File.mtime(Rails.public_path.join("stylesheets/admin.css")).to_i
7
8 assert_equal "#{path}?v=#{expected_mtime}", mtime_busted_path(path)
9 end
10
11 test "mtime_busted_path raises clearly for a missing file rather than silently omitting the version" do
12 assert_raises(RuntimeError) { mtime_busted_path("/stylesheets/does_not_exist.css") }
13 end
14end