loading css files within a static website in heroku - ruby

My config.ru is as follows:
use Rack::Static,
:urls => ["/images"],
:root => "public"
run lambda { |env|
[
200,
{
'Content-Type' => 'text/html',
'Cache-Control' => 'public, max-age=86400'
},
File.open('public/index.html', File::RDONLY)
]
}
When I load it locally the website looks fine, but when I run it on Heroku I get the following error message in the browser console for the CSS files:
Resource interpreted as Stylesheet but transferred with MIME type text/html.
Any idea why I am getting these errors?
Example site: http://salus8.heroku.com.

Your app currently responds to requests in two different ways. Requests starting with /images are served by searching the /public/images folder and returning any file matching the request. Any other request is served by running the lambda block, which returns your index.html file with a content type of text/html.
This applies to any other request, so when your page references a css file and the browser tries to fetch it, your app will return the index.html page with the HTML content type, hence the warning about MIME type.
One way to fix this would be to add /css to the list of urls the Static middleware handles:
use Rack::Static,
:urls => ["/images", "/css"],
:root => "public"
and put your css files in the public/css directory (as I write, it looks like you have already done this).
This would solve your immediate problem, but you might have issues for example if you wanted to have more than one HTML page in the top directory.
Another solution to achieve a static site that serves index.html to any requests with no path, which is what it looks like you're trying to do here, could be to use the rack-rewrite gem and a Rack::File application. Add gem 'rack-rewrite' to your Gemfile, and then use a config.ru like this:
require 'rack/rewrite'
use Rack::Rewrite do
rewrite "/", "/index.html"
end
run Rack::File.new("public")
This will respond to all requests with the matching file (if it exists), and any requests that arrive with no path will get index.html. (Note that it won’t serve index.html for requests for subdirectories under the main directory).
If you’re using Heroku’s Cedar stack, you could also look into faking a php app in order to get “real” static hosting with Apache.
I don’t know why this would be working locally but not on Heroku, unless you’re just opening the files directly in the browser. Are you running a server locally (e.g. with rackup), or looking at the files direct?

Related

serving static files on sinatra

I'm working on a Sinatra app for the first time and am stumbling into an issue with serving a javascript asset.
I am following the Sinatra convention of putting the static files in “public” folder and it works locally but when we create a Docker image, we get a 404 while this works with localhost.
I see where I can set the public_folder which I have tried like this:
http://sinatrarb.com/configuration.html
but still 404'ing. Is there a way to get the top-level object and ask it where it expects the public_folder to be (like Rails.env)?
You can check the settings object.
irb(main):001:0> require "sinatra"
=> true
irb(main):002:0> settings.public_folder
=> "/usr/lib/ruby/2.5.0/irb/public"
This allows you to create a route which returns the path, something like this
require 'sinatra'
get '/' do
settings.public_folder
end
Without more information I would guess that your public folder points to a wrong directory inside your docker because the project :root points to a different directory that what you expect.

Configuring Rack::Static

I'm building a Rack application which serves static and dynamic resources, and I'm trying to use Rack::Static middleware to do this.
The idea is serving all requests for static files and pass the requests that won't match this catogory, the dynamic requests, to my application. But I junt don't know how to do this and the documentation for Rack::Static is not very clear about how to do this.
This is my basic configuration file by now:
config.ru
#\ -w -p 8888
require_relative 'be/emeraldfw/emerald_app'
# use Rack::Reloader, 0
# use Rack::ContentLength
use Rack::Static, :urls => [""], :root => 'public', :index => 'pages/index.html'
run EmeraldApp.new
which just serves requests for / with public/pages/index.html, since the declared root is public.
This is far from being enough.
I need to serve all standard image files from public/resources/images, all CSS files from public/resources/css and so on.
Could someone give a hint about how to do this? I've been fighting this problem for two days now.

How to set HTTP response (cache) headers in a Sinatra app hosted on Heroku

I have a fairly simple app (just one index.html file and a css file - it really is just a static page) hosted on Heroku.
I use Sinatra to host it on Heroku. The 'app' itself is fairly simple:
require 'rubygems'
require 'sinatra'
get "/" do
File.read(File.join('public', 'index.html'))
end
The question is, how do I set the HTTP response header for the static assets? In particular, I wanted to set the Expires header for caching purposes.
EDIT: I'm looking to add the said header to the static assets (ie, the one that resides under /public, like background images, icons, etc)
Apart from the fact that I wouldn't get through the Sinatra stack just to serve static files, you'd call
cache_control :public, max_age: 60
to cache for a minute. cache_control is a helper that comes with Sinatra.
Otherwise, I'd suggest you have a look at http://www.sinatrarb.com/configuration.html to see how Sinatra is set up so you don't have do deal with serving static files.
Hope this helps.
edit: I just saw you were explicitly asking for the Expires header. I'm not sure, but that should be fairly the same way as Cache-Control. Sorry for the confusion
As an expansion to #awendt's answer, Sinatra can actually handle static files with out needing to explicitly define the route and print the file.
By adding:
set :static, true
..you can add your index.html and stylesheet.css to a public/ folder. Then when you visit http://localhost:9292/stylesheet.css you'll be provided with the static file.
If you want to use another folder name, instead of the default public/, then try:
set :public, "your_folder_name"
If we want to be less explicit we can just create the public/ folder in the knowledge that Sinatra will enable :static for us anyway :)
Source: http://www.sinatrarb.com/configuration.html#__enabledisable_static_file_routes

Ruby / Sinatra - serving up css, javascript, or image files

What is the correct way to route your request through Sinatra so that it serves up the file with no processing? I'm looking for the most common way people do this in the Sinatra framework? I normally place all of my static content in a "content" path.
examples:
/content/css
/content/img
/content/js
How can I use a wildcard to serve up everything under content?
I was surprised there were no real examples of this here:
http://sinatra-book.gittr.com/
Sinatra and Rails use the path public for static content - e.g., ./public/javascripts/. All files in these paths would then be served by the web server (e.g. Thin, Passenger), but without the need for /public in the URL (e.g. the file at #{my_app_root}/public/javascripts/application.js would be available via the Web at the URL http://#{my_domain}/javascripts/application.js).
get '/notes/images/:file' do
send_file('/root/dev/notes/images/'+params[:file], :disposition => 'inline')
end

Static page routing in Sinatra (Ruby)

You can serve static files with Sinatra by placing them in public/ (by default) -- I have an index.html in there at the moment, but how can I make the root point to that file without having to parse it as a template?
To be clear, I can access /index.html successfully, and I'd like to route / to be the same static file, but without redirecting. Any idea how to do this?
Probably a better answer will eventually come, until then this is my shot at it.
If this is not what you want:
get '/' do
redirect '/index.html'
end
You might do something like this:
get '/' do
File.new('public/index.html').readlines
end
I'd go with the first one though, Not sure why you want to avoid that redirect
Just set enable :static inside of your app class. Like so:
class App < Sinatra::Base
# Set the app root; this is where the 'public' and 'views'
# directories are found (by default).
set :root, File.expand_path("#{File.dirname(__FILE__)}/../app")
# Allow the app to serve static files from the 'public' directory in :root
enable :static
end
require 'sinatra'
get '/' do
send_file File.join(settings.public_folder, 'index.html')
end
As described at Serving static files with Sinatra
using passenger this seems to work right out of the box. having an index.html file in the public directory and no routing brings up the index.html when accessing the root url.
I think this is only an issue because Sinatra/Rack doesn't have the concept of a default file to serve if you just go to /. In a webserver like Apache or Nginx this is taken care of for you and usually defaults to index.html index.htm (if either exists it will get served when going to a directory with no actual filename on the end).
When everyone says this is built into Passenger, I think they really mean that it's built into Apache/Nginx. Apache/Nginx will check if the static file exists and serve it if it does, the request will never get to Rack, which is awesome for performance.
I wouldn't want to set up a redirect to the 404 page as this sort of violates the whole idea of HTTP: there should be one endpoint for everything that end point should return the true state of that endpoint. Meaning that if you go to /asdf you want the webserver to report a 404 because that's what is actually going on. If you do a redirect, now your site is saying "I used to have something here, but it moved" and then the page it redirects you to, even though it says 404 in the text on the page, is actually reported by the web server as a 200, meaning "everything is fine with this page!"
There is a gem "sinatra-index" to solve this problem.
https://github.com/elitheeli/sinatra-index

Resources