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
Related
I am trying to serve images to my client application with my Sinatra API
when I use this route, it triggers the file download prompt in my browser rather than loading up an image file, how would I go about serving up an image?
get '/images/:project/:img' do
send_file(ProjectPhotos.serve_file(params)) # => triggers a download of file in browser
end
need to add open from the OpenURI library
get '/images/:project/:img' do
send_file open(ProjectPhotos.serve_file(params), type: 'image/jpeg', disposition: 'inline')
end
For serving static images you should use the public folder in Sinatra application root. All files in public folder are served by Sinatra web server without any code needed and the public directory omitted from url.
So "public/yourimage.jpg" is available from "www.yoursite.com/yourimage.jpg"
For more info look at Sinatra documentation.
I have a simple application (server side is Sinatra, client side is ReactJS).
The workflow is very basic: Sinatra handles get "/" request and sends an index.html to the client with static stylesheet and scripts.
Scripts are ReactJS app which consists of several components and a ReactRouter. Each React's component is a distinct "page" with its own route/path in terms of the ReactRouter.
For example:
"/" => "index.html" (real html page with renered components
inside),
"/form" => (ReactRouter points to component <Form/>, in fact render happens inside selector of "index.html"),
"/finish" => (ReactRouter points to component <Finish/>, in fact render happens inside selector of "index.html").
While I was implementing client side only, it worked pretty well. But now, when I am trying to use Sinatra for the server side stuff this is broken: when I want to go to the /form I am getting Sinatra's default 404 page ("Sinatra doesn’t know this ditty.").
I understand that Sinatra (or Rack) intercepts the request's path (/form of /finish) before the ReactRouter. But I cannot understand how to fix it (and why is it so, while router script is already on the client and should fire first).
Thanks for your help.
Use wildcard route to return index.html to all route.
Something like this:
get '/*' do
#return index.html
end
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?
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
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