fix(shell): resolve og:image through the asset pipeline; image is site content

Merged
MH
4mo ago
+285-128

The bug

The og:image on the live docs site pointed at https://docs-kit.zoolutions.llc/og/og.png — which 404s. Propshaft serves the digested asset under /assets/…, not the raw logical path, so a shared link showed a broken image.

Root cause

Two mistakes in the original SEO feature (#49):

  1. Wrong URL construction. DocsUI::MetaTags base-joined the raw og_image path onto the host ("#{base}/#{og_image}") instead of resolving it through the Rails asset pipeline. The result was never a served URL.
  2. Wrong ownership. The gem shipped a default OG image and defaulted og_image to "og/og.png". But the social-share image is each site's own branding — not docs-kit's to render. A site that predates the feature (like the deployed dogfood site) had no such asset precompiled at all, so even a correct URL would 404.

The fix

  • Resolve through the asset pipeline. A relative og_image now goes through image_url → the digested /assets/og/og-<digest>.png URL Propshaft actually serves. An absolute URL passes through untouched. image_url uses Propshaft's Static resolver (needs the asset precompiled), so a misconfigured og_image fails loudly at deploy (assets:precompile) rather than shipping a silent 404 — deliberately not rescued.
  • The image is site content. Removed the gem-shipped image, the generator's copy_file, and the guard spec. c.seo.og_image now defaults to nil → unset emits no og:image tag (a valid card, never a 404, same shape as favicon/robots/theme-color). The docs_kit:og task writes into the site's app/assets/images/.
  • The dogfood /docs site gets its own OG image + c.seo config, so its live card works once deployed.

Why the original tests missed it

The gem's isolated component specs can't exercise the asset pipeline — only a booted app has the Propshaft resolver that turns a logical path into a served /assets URL. So this adds a real integration test in the dogfood site.

Test plan

  • New: docs/test/integration/seo_meta_tags_test.rb — boots the real docs app, GET /, and asserts og:image is a /assets URL and that GETting it returns 200 image/png. That last assertion is the one that reproduces and guards the production 404. Self-precompiles in setup, so it's run-order independent.
  • Updated spec/docs_ui/meta_tags_spec.rb: og:image resolves via the (stubbed) pipeline, is omitted when unset, absolute passes through, and the raw path is never emitted.
  • bundle exec rake → 714 examples, 0 failures (coverage 94.48%), rubocop clean.
  • docs/ integration test → 4 runs, 22 assertions, 0 failures from a clean state.
  • gem build --strict → no image shipped (gem shrank 171K → 134K); component/task/generator still present.
  • Live-parity render: the /docs landing now emits og:image = https://docs-kit.zoolutions.llc/assets/og/og-<digest>.png, which serves 200.

Fixes the 404 reported on https://docs-kit.zoolutions.llc/og/og.png. Refs #48.

https://claude.ai/code/session_01FPQb6z3YwcKRMbvoJhdxnX