Search code examples
rubyroutessinatracustom-routes

Custom :public directory in Sinatra not working


So, I've got a sinatra app I'm working on with the app hosting several different microsites for clients. The way I have my public and views directory structured is like so:

sites/
  site1/
    public/
      style.css
    views/
      layout.haml
      general.haml
  site2/
    public/
      style.css
    views/
      layout.haml
      general.haml

Now, when the request comes in I've got the following two lines:

set :views, Proc.new { File.join(root, "sites/#{site}/views") }
set :public, Proc.new { File.join(root, "sites/#{site}/public") }

When the incoming request comes in, and site gets defined as "site1" the views work exactly as desired with them rendering out of the appropriate folder. However, a call to the "/style.css" route returns a 404 error.

When I make the public directory in the app root and place style.css there it works fine. However, I need this to work on a site-by-site basis. I'm going off of the official docs by Sinatra but it still is not working, even if I set

enable :static

or if I use

set :static, true

As described in the docs. Any ideas?


Solution

  • I imagine this has to do with how you’re setting site. I believe you’ll want to make site a method on your application rather than a static setting, if I understand correctly what you’re asking. This example does that, and worked as expected for me:

    class Test < Sinatra::Base
      set :public, Proc.new { File.join(site, "public") }
      set :static, true
    
      register do
        def site
          ["x", "y", "z"][rand * 3]
        end
      end
    
      get "/" do
        settings.public
      end
    end
    

    However, I’m not sure Sinatra was designed to serve static files this way, and there may be better solutions available anyway. For example, you may be able to do this entirely in Nginx or Apache, bypassing the need to have Sinatra serve static files at all.