How to serve static files via Rack?
To redirect every request to a particular path, use Rack::File
(for some reason this class is absent in recent documentation, but it is still part of the latest Rack):
run Rack::File.new("/my/path")
To redirect every request, and add an HTML index of all files in the target dir, use Rack::Directory
:
run Rack::Directory.new("/my/path")
To combine several directories or serve only a some requests from the target dir:
map "/url/prefix" do
run Rack::File.new("/my/path")
end
# More calls to map if necessary...
# All other requests.
run MyApp.new
Static File serving using Rack
Cuba tries to render a template, so you can rename your file to .mote and it should render ok, or use something like this:
res.headers["Content-Type"] = "text/html; charset=utf-8"
res.write(IO.read('/path/to/your/file.html'))
Source is pretty clear on how the render function works.
How to mount static files for Rack
You need to use Rack::Builder
in order to use the use SomeMiddleware
syntax in a normal Ruby script (it's normally used in a config.ru
file). You also need run
for your application. Note that the urls
key to Rack::Static
takes an array, not a single string:
require 'rack'
Rack::Handler::Thin.run(Rack::Builder.new {
use(Rack::Static, urls: ["/resource/"], root: "/")
run ->env{[200, {}, [some_dyamically_generated_content]]}
}, Port: 3000)
Here Rack::Builder
is taking your application, ->env{[200, {}, [some_dyamically_generated_content]]}
, adding the Rack::Static
middleware to it and creating a new combined application which is then passed to Thin to run.
Rack::Static
is a middleware component that you can add to existing rack applications. Rack::File
and Rack::Directory
are both themselves rack applications, not middleware (Rack::Static
uses Rack::File
internally, as does Rack::Directory
by default). You could achieve the same effect as above using Rack::File
and the map
command:
require 'rack'
Rack::Handler::Thin.run(Rack::Builder.new {
map "/resource/" do
run Rack::File.new "/"
end
map "/" do
run ->env{[200, {}, [some_dyamically_generated_content]]}
end
}, Port: 3000)
The more common way to do this would be to put the contents of the block passed to Rack::Bundler.new
in a config.ru
file:
use(Rack::Static, urls: ["/resource/"], root: "/")
run ->env{[200, {}, [some_dyamically_generated_content]]}
You can then run this with thin start
, which should find config.ru
if run from the same directory, or you can use the -R
option to specify the file. The rackup
command can also be used, rackup -s thin
if you want to specify Thin as the server.
Serve files using Rack TryStatic directly?
As you’ve noticed, a Rack middleware component such as Rack::TryStatic
needs another app to pass requests onto. You could create a simple one to use that for example just returned a 404 response, such as:
app = lambda {|env| [404, {'Content-type' => 'text/plain'}, ['Not found']
run Rack::TryStatic.new app, :root => "build", :urls => %w[/], :try => ['.html']
or equivalently:
use Rack::TryStatic, :root => "build", :urls => %w[/], :try => ['.html']
run lambda {|env| [404, {'Content-type' => 'text/plain'}, ['Not found']]}
If you have your own 404 file, you could use rack-contrib’s Rack::NotFound
instead of a custom end point of your own:
use Rack::TryStatic, :root => "build", :urls => %w[/], :try => ['.html']
run Rack::NotFound.new('path/to/your/404.html')
If you weren’t using the :try
array of file extensions to try and serve, you could use Rack::File
directly. Internally, Rack::TryStatic
uses Rack::Static
, which in turn uses Rack::File
. Unlike TryStatic
and Static
, Rack::File
is a Rack application in its own right, and so doesn’t need a separate app to pass requests to. Your config.ru
would then simply be:
run Rack::File.new './build'
although this wouldn’t allow for “bare” requests to be served with the corresponding .html
file — all requests would need to specify the whole file name.
Rack middleware serve static folders from submodule
It looks like the working directory might be messed with depending on how your Rails application is launched.
I got it working inside a Rails applicaiton with the following config.ru:
# This file is used by Rack-based servers to start the application.
use Rack::Static, :urls => ["/folder_a", "/folder_b"], :root => ::File.expand_path("submodule/public")
require ::File.expand_path('../config/environment', __FILE__)
run Rails.application
Then in a terminal:
$ rails server -d
=> Booting WEBrick
=> Rails 4.2.0 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
$ curl http://0.0.0.0:3000/folder_a/index.html
A
$ curl http://0.0.0.0:3000/folder_b/index.html
B
Pow config.ru for serving static files outside of the public directory?
You could use TryStatic
from rack-contrib:
require 'rack/contrib/try_static'
use Rack::TryStatic,
:root => "html",
:urls => %w[/]
You might want to add if ENV['RACK_ENV'] == 'development'
if you only want this during development (e.g. if your web server is configured to serve from html/
)
.
Related Topics
How to Get the Name of a Ruby Class
How to Use CSS with a Ruby on Rails Application
Ruby: Installing Rmagick on Ubuntu
Ruby on Rails - Unable to Convert "\X89" from Ascii-8Bit to Utf-8 for Xxx/Xxxx/Xxxx
Why Is Sudo: Bundle Command Not Found
Launching Background Process in Capistrano Task
Google Plus API Shutdown Today, Which Alternative Can Be Used to Authentication
How to Add an Array to Another Array in Ruby and Not End Up With a Multi-Dimensional Result
How to Do Relative Time in Rails
Ruby: What Does the Comment "Frozen_String_Literal: True" Do
How to Understand the Difference Between Class_Eval() and Instance_Eval()
How to Set a File Upload Programmatically Using Paperclip
How to "Activate" a Different Version of a Particular Gem
How to Write Postgresql Functions on Ruby on Rails
Purpose of "Consider_All_Requests_Local" in Config/Environments/Development.Rb