Calling Sinatra from Within Sinatra

Calling Sinatra from within Sinatra

I was able to hack something up by making a quick and dirty rack request and calling the Sinatra (a rack app) application directly. It's not pretty, but it works. Note that it would probably be better to extract the code that generates this resource into a helper method instead of doing something like this. But it is possible, and there might be better, cleaner ways of doing it than this.

#!/usr/bin/env ruby
require 'rubygems'
require 'stringio'
require 'sinatra'

get '/someresource' do
resource = self.call(
'REQUEST_METHOD' => 'GET',
'PATH_INFO' => '/otherresource',
'rack.input' => StringIO.new
)[2].join('')

resource.upcase
end

get '/otherresource' do
"test"
end

If you want to know more about what's going on behind the scenes, I've written a few articles on the basics of Rack you can read. There is What is Rack? and Using Rack.

How to call a Sinatra route from IRB console

I discovered the Tux gem. It allows calling of get and post routes from within IRB console.

Sinatra route function call & helpers

You've overcomplicated things. See the Helpers section of docs.

Put this in your Application controller:

helpers do
def render
@page = Page.find_by permalink: request.path_info
if @page then
else
halt 400
end
end
end

Now your route will be:

get '/*' do
render
end

Still, too complicated if you ask me, no need to ape Rails. Why not keep it simple?

require 'sinatra'

get '/*' do
@page = Page.find_by permalink: request.path_info
if @page then
haml :something
else
halt 400
end
end

That's it, that's the whole Sinatra app without recourse to inheritance and a structure that isn't required. Unless you're adding pages dynamically after the app is deployed then I'd also define the routes more explicitly.

Don't use globals. I actually can't remember the last time I saw one used, there are so many better alternatives. If you find you need one it's a clue you're going down the wrong path.

Calling a Sinatra app instance method from TestCase

Sinatra aliases the new method to new! before redefining it, so the simplest solution is to use that instead:

def app
MyApp.new!
end

Of course I only noticed that after I’d come up with the following, which I’ll leave in as it could be useful/informative.


A possible way to get round Sinatra redefining the new method and returning a complete Rack app a get hold of an instance your actual base class is to do what the “real” new method does yourself:

def app
a = MyApp.allocate
a.send :initialize
a
end

This is a bit of a hack, but it might be useful for testing.

Another technique would be to “walk” the middleware stack until you got to your class. The following is a little fragile, as it depends on all the middleware involved to use the name @app to refer to the next app in the stack, but this is fairly common.

def app
a = MyApp.new
while a.class != MyApp
a = a.instance_variable_get(:@app)
end
a
end

That won’t work on the yet to be released Sinatra 1.4 though (at least not on the current master, which is commit 41840746e866e8e8e9a0eaafc53d8b9fe6615b12), as new now returns a Wrapper class and the loop never ends. In this case you can grab the base class directly from the @instance variable:

def app
MyApp.new.instance_variable_get :@instance
end

(note this last technique may well change before the final 1.4 release).

Call erb within an external class in sinatra

You can achieve this by creating a helpers module for your methods:

# module instead of a class
module MyHelpersModule
# no need for 'self'
def some_function(request)
erb :some_template
end
end

Then in your main app file call helpers MyHelpersModule. This will make all the methods in MyHelpersModule available in your application and also, since they are executed in the same context, the existing Sinatra methods (like erb) will be available to your helpers.

require 'sinatra'
require './my_helpers_module'

helpers MyHelpersModule

get '/' do
some_function(request)
end


Related Topics



Leave a reply



Submit