Static page routing in Sinatra (Ruby) - 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

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.

Modular Sinatra app returns 404's under Passenger

I have a modular Sinatra app which runs fine when executed with rackup. The config.ru file is defined as follows:
map '/' do
run My::Controllers::Default
end
map '/api' do
run My::Controllers::Api
end
When I run the app under nginx/passenger I get nothing but 404's, even for the '/' route. Suspecting that something was wrong with routing, I modified config.ru as follows:
run My::Controllers::Default
After restarting nginx, I was served the default page of the app. However, the default page of the app reaches into the api route to get some documentation to display, and that part returns a 404. Given that config.ru is able to run the Default controller, I'm sure that the issue has nothing to do with being able to load all of the relevant ruby files--which seems to be the problem in other related questions I've found on SO.
With that in mind I modified config.ru as follows:
map '/api' do
run My::Controllers::Api
end
run My::Controllers::Default
At this point I'm back to getting nothing but 404's, even for the '/' route. It seems that the map statement is confusing the webserver and making it unable to find the correct routes.
If I just run the app using rackup everything behaves as expected, so I'm really at a loss to explain what I'm seeing.
I remember this being the answer. Let me know if it works for you. If it does I'll "Accept" the answer so that others will find it.
Middleware
A bug in passenger prevents it from understanding the map statement in config.ru https://groups.google.com/forum/#!msg/phusion-passenger/PoEEp9YcWbY/1y0QL_i3tHYJ
class PassengerFix
def initialize(app)
#app = app
end
def call(env)
env["SERVER_NAME"] = env["HTTP_HOST"]
return #app.call(env)
end
end
config.ru
configure do
use PassengerFix
end

Jekyll site via Sinatra and Heroku - can't route to new posts

I created a 'Hello, World' app using Sinatra and then pushed to Heroku and all worked.
I've since created a basic Jekyll blog, and am trying to access it via Heroku using the following routes:
get '/?' do
file.read("_site/index.html")
end
get '/.*.*' do
file.read("_site/#{params[:splat]}")
end
not_found do
file.read("_site/error/index.html")
end
The route to the index works fine link to my site
but as soon as I click to the first post it always fails.
I have tried so many variations of different routes for the :splat and get, just can't seem to get it to work? Any ideas?
In the route that's failing, before the file.read statement, add warn "splat = #{params[:splat]}" and that will output the result to the terminal, and you can see what it's actually getting, e.g.
get '/.*.*' do
warn "splat = #{params[:splat]}"
file.read("_site/#{params[:splat]}")
end
You could also try using an absolute path to the files, though if you're getting the index page then it suggests it's not needed:
config do
set :statics, File.expand_path(File.join(settings.root, "_site"))
end
get '/.*.*' do
file.read( File.join settings.statics, params[:splat] )
end
Unless there's something else you were planning to use Sinatra's routes for, you could probably remove the Sinatra routes entirely and just make the "_site" folder the public_folder, and then Sinatra will do the serving of the static files for you:
config do
set :public_folder, File.expand_path(File.join(settings.root, "_site"))
end
# no more to do...

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

Resources