143

I have one page website only using HTML, CSS and JavaScript. I want to deploy the app to Heroku, but I cannot find a way to do it. I am now trying to make the app working with Sinatra.

.
|-- application.css
|-- application.js
|-- index.html
|-- jquery.js
`-- myapp.rb

And the following is the content of myapp.rb.

require 'rubygems'
require 'sinatra'

get "/" do
  # What should I write here to point to the `index.html`
end
TK.
  • 27,073
  • 20
  • 64
  • 72
  • 1
    I have learnt that accessing http://localhost:2345/index.html works. – TK. Mar 20 '10 at 11:11
  • You can use WebBrick to serve static files in a few lines. `require 'webrick'; server = WEBrick::HTTPServer.new Port: 1234; server.mount '/', WEBrick::HTTPServlet::FileHandler, 'www/'; trap("INT") { server.stop }; server.start;` Then run `ruby myapp.rb`. Remove the port for Heroku. Put `web: ruby myapp.rb` in your `Procfile`. Comment not answer as it's not for Sinatra, but I think it simplifies dependencies. – Chloe Jan 16 '16 at 07:09

14 Answers14

169

You can use the send_file helper to serve files.

require 'sinatra'

get '/' do
  send_file File.join(settings.public_folder, 'index.html')
end

This will serve index.html from whatever directory has been configured as having your application's static files.

Chad DeShon
  • 4,732
  • 6
  • 28
  • 29
Ryan Ahearn
  • 7,886
  • 7
  • 51
  • 56
  • 19
    I think newer Sinatra apps use `set :public_folder`, so you would use `settings.public_folder` instead of `settings.public` – Andrew Nov 10 '11 at 16:55
  • 4
    I updated the answer to use settings.public_folder. Older apps may still need to use settings.public. – Chad DeShon Feb 20 '12 at 15:50
133

Without any additional configuration, Sinatra will serve assets in public. For the empty route, you'll want to render the index document.

require 'rubygems'
require 'sinatra'

get '/' do
  File.read(File.join('public', 'index.html'))
end

Routes should return a String which become the HTTP response body. File.read opens a file, reads the file, closes the file and returns a String.

Tate Johnson
  • 3,910
  • 1
  • 23
  • 21
  • 54
    You should rather do `send_file File.expand_path('index.html', settings.public)`. – Konstantin Haase Jan 04 '12 at 16:31
  • 33
    This is now incorrect. You should replace `settings.public` with `settings.public_folder` to get `send_file File.expand_path('index.html', settings.public_folder)` – Alistair Holt Feb 04 '13 at 18:18
  • 2
    @zhirzh `send_file`, it does extra stuff for you https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L351 – ian Dec 10 '15 at 23:07
  • 1
    `File.read` reads the entire file into memory. This can be OK or not, depending upon the size of the files and the number of concurrent requests. – Wayne Conrad Sep 14 '16 at 19:30
  • @WayneConrad on the opposite, send_file is okay ? or it acts the same ? – Ben Mar 01 '17 at 05:23
  • @Ben I do not know, but I would be surprised if `send_file` did not handle large files gracefully. – Wayne Conrad Mar 01 '17 at 16:04
65

You could just host them from the public folder and they do not need routes.

.
-- myapp.rb
`-- public
    |-- application.css
    |-- application.js
    |-- index.html
    `-- jquery.js

In the myapp.rb

set :public_folder, 'public'

get "/" do
  redirect '/index.html'
end

Link to some sub folder in public

set :public_folder, 'public'
get "/" do
  redirect '/subfolder/index.html' 
end

Everything in ./public is accessible from '/whatever/bla.html

Example :
./public/stylesheets/screen.css
Will be accessible via '/stylesheets/screen.css' no route required

Morgan
  • 19,934
  • 8
  • 58
  • 84
  • 1
    what if public has many nested folders (for which you don't want to create routes) that have index.html files you would like to be the default? – Derek Prior Apr 27 '12 at 13:51
  • I have expanded the solution. I hope it helps clarify, everything is accessible in public, no route required just omit the 'public' part of the path. – Morgan Apr 28 '12 at 16:12
  • 1
    using rackup on Heroku I had to use `set :public_folder, 'public'`. That was key to making it work, despite Sinatra documentation implying that this was already set as default. – Daniel C Jan 21 '14 at 22:36
12

Keep in mind that in production you can have your web server send out index.html automatically so that the request never gets to Sinatra. This is better for performance as you don't have to go through the Sinatra/Rack stack just to serve static text, which is what Apache/Nginx are awesome at doing.

Rob Cameron
  • 9,674
  • 7
  • 39
  • 42
  • Oh yeah, duh. I'll just use Erb then and use Varnish to cash it. – ma11hew28 Feb 14 '11 at 23:33
  • 3
    How do you configure this in production? I've been searching for documentation about this cross referencing with Sinatra and Rack but can't find it. Basically I want index.html to be loaded in any /public folder that has one if the user only puts the folder name –  Apr 25 '13 at 18:47
10

Sinatra should let you serve static files from the public directory as explained in the docs:

Static Files

Static files are served from the ./public directory. You can specify a different location by setting the :public option:

Note that the public directory name is not included in the URL. A file ./public/css/style.css is made available as example.com/css/style.css.

Community
  • 1
  • 1
  • 6
    Why does this have 4 votes? It doesn't answer the question of how to present a default document when a folder is requested. – Derek Prior Apr 27 '12 at 13:49
6

Add below line in main rb file

set :public_folder, 'public'

ref: http://sinatrarb.com/configuration.html#static---enabledisable-static-file-routes

3

http://sinatrarb.com/configuration.html#static---enabledisable-static-file-routes

This would be the correct way of doing it.

set :public_folder, 'public'

I used the static setting because it's setting can affect the public_folder usage.

Hayden
  • 2,082
  • 1
  • 14
  • 18
3

You can always use Rack::Static

https://www.rubydoc.info/gems/rack/Rack/Static

Just add this line before 'run' command into 'config.ru'

use Rack::Static, :urls => [""], :root => 'public', :index => 'index.html'
r0ma
  • 133
  • 1
  • 5
2

the sinatra-assetpack gem offers a whole bunch of features. syntax is sweet:

serve '/js', from: '/app/javascripts'

while i am still having issues with rails assets pipeline i feel like i have much more control using sinatra-assetpack - but most of the times it just works with a few lines of code.

jitter
  • 434
  • 8
  • 16
2

UPDATED ANSWER: I tied all the above with no luck of being ablle to load css, js....etc contents the only thing that was loading is index.html... and the rest were going =>> 404 error

My solution: app folder looks like this .

index.rb ==>> Sinatra code goes .

require 'rubygems'
require 'sinatra'

get '/' do
  html :index
end

def html(view)
  File.read(File.join('public', "#{view.to_s}.html"))
end

public folder==>> contains everything else ...css , js , blah blah..etc.

user@user-SVE1411EGXB:~/sintra1$ ls
index.rb  public
user@user-SVE1411EGXB:~/sintra1$ find public/
public/
public/index.html
public/about_us.html
public/contact.html
public/fonts
public/fonts/fontawesome-webfont.svg
public/fonts/fontawesome-webfont.ttf
public/img
public/img/drink_ZIDO.jpg
public/js
public/js/bootstrap.min.js
public/js/jquery.min.js
public/js/bootstrap.js
public/carsoul2.html
public/css
public/css/font-awesome-ie7.css
public/css/bootstrap.min.css
public/css/font-awesome.min.css
public/css/bootstrap.css
public/css/font-awesome.css
public/css/style.css
user@user-SVE1411EGXB:~/sintra1$

Now start server and you will be able to navigate through static pages with no problem.

user@user-SVE1411EGXB:~/sintra1$ ruby index.rb 
== Sinatra/1.4.5 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.5.1 codename Straight Razor)
>> Maximum connections set to 1024
>> Listening on localhost:4567, CTRL+C to stop
z atef
  • 7,138
  • 3
  • 55
  • 50
2
require 'rubygems'
require 'sinatra'

set :public_folder, File.dirname(__FILE__) + '/../client'
#client - it's folder with all your file, including myapp.rb

get "/" do
  File.read('index.html')
end
Vlad Hilko
  • 1,104
  • 12
  • 17
1

You might consider moving the index.html file to views/index.erb, and defining an endpoint like:

get '/' do
  erb :index
end
bonh
  • 2,863
  • 2
  • 33
  • 37
0

Putting files in public folder has a limitation. Actually, when you are in the root '/' path is works correctly because the browser will set the relative path of your css file for example /css/style.css and sinatra will look for the file in the public directory. However, if your location is for example /user/create, then the web browser will look for your css file in /user/create/css/style.css and will the fail.

As a workaround, I added the following redirection to correctly load css file:

get %r{.*/css/style.css} do
    redirect('css/style.css')
end
Charmi
  • 594
  • 1
  • 5
  • 20
-7

What about this solution? :

get "/subdirectory/:file" do 
  file = params[:file] + "index.html"
  if File.exists?(params[:file])
    return File.open("subdirectory/" + file)
  else
   return "error"
  end
end

so if you now navigate to (for example) /subdirectory/test/ it will load subdirectory/test/index.html

heldopslippers
  • 828
  • 2
  • 9
  • 20