Sinatra: stack level too deep - ruby

There is a code sample from Sinatra: Up and Running(Example 4-22). When I try to run it, the following result is given: stack level too deep.
require 'sinatra/base'
class ApplicationController < Sinatra::Base
def self.inherited(sublass)
super
use sublass
end
enable :logging
end
# works with dynamically generated applications, too
Sinatra.new ApplicationController do
get '/' do
"See the <a href='/example'>example</a>."
end
end
ApplicationController.run!
Indeed, this code looks wrong, because the new app extends AppController and when AppController use the app it will recur forever.
Then how to do this right?

Try something like this:
class SinatraApp < Sinatra::Base
get '/' do
"See the <a href='/example'>example</a>."
end
end
run SinatraApp.new

Related

Sinatra App - Separating Concerns

Probably something really basic, but I want to be able to separate my Sinatra routes from controllers. I have this code in my routes.rb:
require 'sinatra/base'
class Server < Sinatra::Base
get '/' do
Action.index
end
end
This is my controller/server.rb
class Action
def sef.index
#user = User.new("Abiodun Shuaib")
haml: index
end
end
It gives the error undefined method 'haml' in Action:Class.
How can I fix this?
You are trying to access method haml in class Action. It simply doesn't contain it.
For example, you can do:
class Server
def index
#user = User.new("Abiodun Shuaib")
haml :index
end
end
By doing this, you will add to Server method index.
Or you can do in such way(it's called Mixin):
module ActionNew
def index
#user = User.new("Abiodun Shuaib")
haml :index
end
end
class Server < Sinatra::Base
include ActionNew
get '/' do
index
end
end

How can you set up scoped redirects for Sinatra apps

I have a series of sinatra applications that are set up such that each is responsible for one thing.
Let's say I have two apps like this:
class Foo < Sinatra::Base
get '/' do
'FOO!'
end
end
class Zoo < Sinatra::Base
get '/' do
'ZOO!'
end
get '/zoom' do
# do things
redirect '/'
end
end
Now let's say I have my config.ru as such:
require './application'
run Rack::URLMap.new('/' => Foo.new, '/zoo' => Zoo.new)
The problem I'm running into is when I try to do the redirect in the zoom action I get sent off to the index action of Foo instead of Zoo. Is there a clean way to do this such that my applications don't need to know how the routes are set up for the app?
You can use configurable redirects. See http://www.sinatrarb.com/2011/03/03/sinatra-1.2.0.html#configurable_redirects.
E.g.
class Zoo < Sinatra::Base
get '/' do
'ZOO!'
end
get '/zoom' do
# do things
redirect to('/')
end
end
Or alternatively, as mentioned in the link above, skip the to() call by enabling prefixed redirects in the Zoo app:
class Zoo < Sinatra::Base
enable :prefixed_redirects
...

Modular Sinatra App using Sinatra Reloader?

Hi if I had a 'main' sinatra file with the following code,
require 'sinatra'
require "sinatra/reloader"
class MyApp < Sinatra::Base
configure do
require "./rest/auth.rb"
register Sinatra::Reloader
also_reload '/rest/auth'
end
get '/' do
erb :home
end
end
And I wanted to put my authentication logic inside of /rest/auth.rb, how can I get /rest/auth.rb to reload in development mode? Must I put the configure block and require sinatra/reloader in every one of my controller files? I'd like for my controllers to inherit the settings of my main class. The code inside of auth.rb is as follows:
class MyApp < Sinatra::Base
set(:auth) do |*roles| # <- notice the splat here
condition do
unless logged_in?
session[:success_url] = request.path_info
redirect '/'
end
end
end
def logged_in?
current_user
end
def current_user
if session[:user_id]
u = User.find(:id=>"#{session[:user_id]}")
else
false
end
end
end
I need to restart the server for my changes to take place but I can throw that reload code in auth.rb's configure block though I wouldn't like to. Any ideas?
Try to rewrite like this
require 'sinatra/base'
require "sinatra/reloader"
class MyApp < Sinatra::Base
configure :development do
register Sinatra::Reloader
also_reload './rest/auth'
end
require "./rest/auth.rb"
get '/' do
erb :home
end
end

Sinatra : how to use helpers in Mustache views

I want to use my Sinatra helpers methods in Mustache views.
I do this:
# in app.rb:
...
helpers do
def helloworld
"helloworld!"
end
end
get '/'
mustache :home
end
...
# in views/home
class App < Sinatra::Base
module Views
class Home < Mustache
def hello
helloworld
end
end
end
end
# in home.mustache
<p>{{hello}}</p>
It does not work, I have the error message :
«undefined local variable or method `helloworld' for App::Views::Home:0x000000023ebd48»
How can I use my method helper in Mustache view ?
Or, how can I use my method helper directly from home.mustache ? like this :
# in home.mustache
<p>{{helloworld}}</p>
Many thanks for your help!
You should be able to do something with a module:
# app_helpers.rb
module AppHelpers
def helloworld
"helloworld!"
end
end
# app.rb
helpers AppHelpers
get '/'
mustache :home
end
# views/home.rb
class App < Sinatra::Base
module Views
class Home < Mustache
include AppHelpers
def hello
helloworld
end
end
end

How to share the error and not_found handlers in Sinatra

I am creating a web app using Ruby and Sinatra, and I'm splitting up the various aspects into separate Sinatra::Base classes, like so:
class Frontend < Sinatra::Base
get '/' do
erb :home
end
end
class Backend < Sinatra::Base
get '/account' do
erb :account
end
end
Now I want to use the not_found and error routes, but I don't want to duplicate them in both classes.
What's the best way to declare them once and have them apply to routes in both classes?
class SomeAwesomeClassName < Sinatra::Base
get '/not_found' do
end
get '/error' do
end
end
class MyApp < Sinatra::Base
use SomeAwesomeClassName
get '/' do
end
end

Resources