Search code examples
rubysinatraassetssprockets

Sinatra show view /example/:id returns 404 error for assets, when using sprockets


When I am accessing:

get "/example/:id" do
  ...
  slim :'example/show'
end

I am getting this error:

"GET /example/assets/app.css HTTP/1.1" 404
"GET /example/assets/app.js HTTP/1.1" 404

I am suspecting that :id can be a problem here, because my assets setup works when I am accessing:

get "/example" do
  ...
  slim :'example/index'
end

works:

"GET /assets/app.css HTTP/1.1" 304
"GET /assets/app.js HTTP/1.1" 200 

My setup for sprockets:

class App < Sinatra::Base
  set :environment, Sprockets::Environment.new

  environment.append_path "assets/stylesheets"
  environment.append_path "assets/javascripts"

  environment.js_compressor  = :uglify
  environment.css_compressor = :scss

  get "/assets/*" do
    env["PATH_INFO"].sub!("/assets", "")
    settings.environment.call(env)
  end

  ...

end

My full repo but without last changes: https://github.com/aneta-bielska/home-for-paws-app


Solution

  • In your layout you have the following lines which define the links to your assets:

    link rel="stylesheet" href="assets/app.css"
    script src="assets/app.js"
    

    Since the urls in these elements don’t start with a slash, the browser treats them as relative to the page where they appear. This means that when you visit /example the links go to /assets/app.cs and /assets/app.js. However when you go to e.g example/1 the links are treated as relative to the 1, so the browser tries to fetch /example/assets/app.cs (and similarly for app.js).

    You need to make sure theses links are always treated as absolute. The simplest way would be to just add a / at the start:

    link rel="stylesheet" href="/assets/app.css"
    script src="/assets/app.js"
    

    A more robust solution might be to use Sinatra’s url helper to ensure you always create the correct links, as it will take it account mounting the app at different paths on the server:

    link rel="stylesheet" href=url("/assets/app.css")
    script src=url("/assets/app.js")