Configuring Rack::Static - ruby

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.

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.

loading css files within a static website in heroku

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?

Multiple Sinatra apps using rack-mount

I have a question regarding using rack-mount with Sinatra. I've got two classic-style Sinatra apps. Let's call one App defined in app.rb and the other API defined in api.rb.
I would like it so that api.rb handles all routes beginning with '/api' and app.rb handles all other requests including the root ('/').
How would I set this up with rack-mount? Or is there a better solution than that?
I think you'll prefer Rack::URLMap - it will probably look something like this:
run Rack::URLMap.new("/" => App.new,
"/api" => Api.new)
That should go in your config.ru file.
I had a similar issue and I am not very familiar with Rack. I could not figure out what to do based on the answers above. My final solution was to have the following in config.ru.
This works perfectly for me.
# Main Ramaze site
map "/" do
Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8
require ::File.expand_path('../app', __FILE__)
Ramaze.start(:root => __DIR__, :started => true)
run Ramaze
end
# Sinatra & Grape API
map "/api" do
use Rack::Static, :urls => ["/stylesheets", "/images", "/javascripts"], :root => "public"
use Rack::Session::Cookie
run Rack::Cascade.new([
MySinatraApp::Application,
MySinatraApp::API])
end
In config.ru you could also take advantage of Sinatra's middleware feature. If you have several Sinatra apps, each with its own routes, and want to run them simultaneously, you can arrange them in the order you want them found, e.g.
# config.ru
...
use MyAppA
use MyAppB
use MyAppC
run MyAppD
I had the same problem once and so I came up with this template: sinatra-rspec-bundler-template which is layed out for multiple apps.
It may have more features than you need but it should help you when you need something "a bit more" complex.

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