sellarafaeli
sellarafaeli

Reputation: 1177

Sinatra - render "erb" within Module

How can I use erb within a Module in Sinatra? Here is an example of a complete app, where erb fails within a Module.

require 'sinatra'

get '/yes' do
  erb "<%= Time.now %>" #works
end

get '/no' do 
  MyMod.foo #fails
end

module MyMod
  extend self

  def foo
    erb "<%= Time.now %>" #fails: undefined method `erb' for MyMod:Module
  end
end

Upvotes: 1

Views: 1493

Answers (4)

Daniel Garmoshka
Daniel Garmoshka

Reputation: 6352

Extending answer of @Sergio Tulentsev: To imitate rendering behavior of Sinatra controller you can create module like this:

module ErbRender

  include Sinatra::Templates
  include Sinatra::Helpers
  include Sinatra::ContentFor

  def settings
    @settings ||= begin
      settings = Sinatra::Application.settings
      settings.root = "#{ROOT}/app"
      settings
    end
  end

  def template_cache
    @template_cache ||= Tilt::Cache.new
  end

end

Here you may need to tune settings.root

Usage example:

class ArticleIndexingPostBody

  include ErbRender

  def get_body
    erb :'amp/articles/show', layout: :'amp/layout'
  end

end

This will properly render templates with layouts including content_for

Upvotes: 1

sellarafaeli
sellarafaeli

Reputation: 1177

Solution - call erb on a Sinatra::Application instance, as below (two ways of calling it, second one is preferable).

require 'sinatra'

get '/yes' do
  erb "<%= Time.now %>" #works
end

get '/foo' do 
  MyMod.foo #works
end

get '/foo2' do
  MyMod.foo2 #works 
end

module MyMod 
  extend self

  def foo
    ObjectSpace.each_object(Sinatra::Application).first.erb "<%= Time.now %>"
  end

  def foo2
    @app ||= Sinatra::Application.new.instance_variable_get :@instance
    @app.erb "<%= Time.now %>"
  end 
end

Upvotes: 0

Bala
Bala

Reputation: 11254

This may not be the answer you are looking for. Here is my another version. Probably this is close to what you wanted to achieve.

module MyMod  
  extend self

  def foo
    ERB.new("<%= Time.now %>").result   
  end
end

get '/' do
   MyMod.foo
end

or with helpers??

module Sinatra
    module MyMod  
        def foo
            erb "<%= Time.now %>"
        end
    end
    helpers MyMod
end

get '/' do
    foo
end

Upvotes: 2

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230356

The erb method is defined in Sinatra::Templates. So one would think he'd be able to just use that

module MyMod
  extend Sinatra::Templates
  extend self

  def foo
    erb Time.now.to_s
  end
end

However, it's not that simple. Now erb method is found, but still doesn't work

NameError at /no

undefined local variable or method `settings' for MyMod:Module

If you follow that rabbit hole, you'll need to make your module a full sinatra app (don't know if that's even possible).

Why don't you use a modular sinatra app style (create a class which inherits from Sinatra::Base) and include your module into the app? This way I'm quite confident it'll "just work".

Upvotes: 3

Related Questions