I want to serv static files as well as dynamic contents through Rack. Previously, I used WEBrick without using Rack, with code like this, and it worked:
@s = WEBrick::HTTPServer.new(
Port: 3000,
BindAddress: "localhost",
Logger: WEBrick::Log.new(File::NULL),
AccessLog: [nil, nil]
)
%w[INT TERM].each{|signal| trap(signal){@s.shutdown}}
@s.mount("/", self)
@s.mount("/resource/", WEBrick::HTTPServlet::FileHandler, "/")
@s.start
In the above, requests to localhost:3000
will be responded by dynamic contents, and requests to localhost:3000/resource/path_to_file
will be responded by a static file located at /path_to_file
on my computer.
Now, I want to switch to a system using Rack with Thin server. I wrote the following, but could not get the static files served. How should it be changed to make it work?
Rack::Handler::Thin.run(->env{
h = Rack::Utils.parse_nested_query(env["QUERY_STRING"])
# I tried the following three lines one at a time, but neither worked.
use(Rack::Static, urls: "/resource/", root: "/") # First try
Rack::File.new("/resource").call(env) # Second try
Rack::Directory.new("/resource").call(env) # Third try
[200, {}, [some_dyamically_generated_content]]
}, Port: 3000)
I know that ther is a similar question: How to serve static files via Rack?, but I could not make it work. I am not sure how to use Rack::Static
, Rack::File
, or Rack::Directory
. Please teach me.
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.
If you don't require authentication/authorization before serving the files you should be able to add files into /public
and have them be served by the underlying server.
So if your app layout looks like this
my_app/
- app.rb
- config.ru
- public/
- a_static_file.png
- another_static_file.png
Once you start your app (using thin, webrick, or apache or whatever underlying server) you can access the static files from http://localhost:4567/a_static_file.png
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With