How to turn a config.ru file into a single Rack application?
rack, ruby
Solution
The DSL used in `config.ru` is defined in `Rack::Builder`. When using a `config.ru`, contents of the file are passed to an instance of `Builder` to create the Rack app. You can do this directly yourself in code.
For example, you can take the contents of your existing `config.ru`, and create a new class from it:
require 'rack'
class MyApp
def initialize
@app = Rack::Builder.new do
# copy contents of your config.ru into this block
map '/route1' do
run SampleApp.new
end
map '/route2' do
run SampleApp.new
end
end
end
def call(env)
@app.call(env)
end
end
You need the `call` method so that your class is a Rack app, but you can just forward the request on to the app you create with `Builder`. Then you can create your new `config.ru` that uses your new app:
require './my_app'
run MyApp.new
Problem
I have a config.ru file that is starting to have duplicate code: ``` map '/route1' do run SampleApp.new end map '/route2' do run SampleApp.new end ``` I would like to turn this config.ru file into its own Rack application so that all I have to do is: ``` map '/' do run MyApp.new end ``` What is the correct way to create your own Rack application? Specifically, how can I create a class so that I can use the `map` method within my class to define a bunch of routes? Solution: Here is a working solution: ``` class MyApp def initialize @app = Rack::Builder.new do # copy contents of your config.ru into this block map '/route1' do run SampleApp.new end map '/route2' do run SampleApp.new end end end def call(env) @app.call(env) end end ``` I tried this before, but couldn't get it to work because I was trying to pass instance variables to the `map` blocks. For example: ``` def initialize @sample_app = SampleApp.new @app = Rack::Builder.new do map '/route1' do run @sample_app # will not work end end end ``` The reason this will not work is because the block being passed to `map` is being evaluated in the context of a `Rack::Builder` instance. However, it will work if I pass a local variable: ``` def initialize sample_app = SampleApp.new @app = Rack::Builder.new do map '/route1' do run sample_app # will work end end end ```