【问题标题】:Sinatra - render "erb" within ModuleSinatra - 在模块中渲染“erb”
【发布时间】:2015-05-13 07:50:31
【问题描述】:

如何在 Sinatra 的模块中使用erb?这是一个完整应用程序的示例,其中 erb 在模块中失败。

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

【问题讨论】:

    标签: ruby sinatra


    【解决方案1】:

    erb 方法在Sinatra::Templates 中定义。所以有人会认为他可以使用它

    module MyMod
      extend Sinatra::Templates
      extend self
    
      def foo
        erb Time.now.to_s
      end
    end
    

    然而,事情并没有那么简单。现在erb方法找到了,但是还是不行

    NameError at /no

    MyMod:Module 的未定义局部变量或方法“设置”

    如果你遵循那个兔子洞,你需要让你的模块成为一个完整的 sinatra 应用程序(不知道这是否可能)。

    您为什么不使用模块化 sinatra 应用程序样式(创建一个继承自 Sinatra::Base 的类)并将您的模块包含到应用程序中?这样我就很有信心它会“正常工作”。

    【讨论】:

    • 是的,这就是我要进入的兔子洞……我会试试你的建议。但是没有办法将 Sinatra 的 'erb' 与常规 Sinatra 模块一起使用吗?
    • 没有“常规 sinatra 模块”之类的东西 :)
    • :) 我的意思是,一个普通的 Ruby 模块。
    • erb 如果您满足它的所有依赖项(例如这里的 settings 方法)和所有它们的依赖项,它将很高兴地工作。最简单的方法是将所述模块包含在真正的 sinatra 应用程序类中(显然,您不需要包含 Sinatra::Templates。)
    • 你为什么还要在这里使用一个模块?我看不出目的。
    【解决方案2】:

    这可能不是您正在寻找的答案。这是我的另一个版本。这可能接近您想要实现的目标。

    module MyMod  
      extend self
    
      def foo
        ERB.new("<%= Time.now %>").result   
      end
    end
    
    get '/' do
       MyMod.foo
    end
    

    还是有帮手??

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

    【讨论】:

    • 你不需要字符串插值。
    • 是的,我特意问的是如何在模块内进行渲染,而不是在渲染前返回主应用。
    • 我看到你改变了一点:) - 这确实更接近。我宁愿使用 Sinatra 自己的“erb”(为了兼容性);至少我需要弄清楚如何传递 ERB.new 参数和布局文件(这基本上是 Sinatra 的“erb”的主要用例..)
    • @sellarafaeli re参数,你的意思是ERB.new("#{params['aaa']}").result
    • @sellarafaeli 还有,那个 ERB.new 行不是 sinatra 自己的 ERB。如果您启动 irb,然后输入 require 'erb',那么您会看到 ERB.new 行有效。甚至还有一个命令行 erb。如果我执行 which erb,我会看到 /usr/local/bin/erb
    【解决方案3】:

    @Sergio Tulentsev 的扩展答案: 要模仿 Sinatra 控制器的渲染行为,您可以像这样创建模块:

    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
    

    这里你可能需要调settings.root

    使用示例:

    class ArticleIndexingPostBody
    
      include ErbRender
    
      def get_body
        erb :'amp/articles/show', layout: :'amp/layout'
      end
    
    end
    

    这将正确呈现具有包括content_for在内的布局的模板

    【讨论】:

      【解决方案4】:

      解决方案 - 在 Sinatra::Application 实例上调用 erb,如下所示(两种调用方式,第二种更好)。

      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
      

      【讨论】:

        猜你喜欢
        • 2013-02-16
        • 2012-06-03
        • 2014-01-24
        • 1970-01-01
        • 2012-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-14
        相关资源
        最近更新 更多