【问题标题】:How to use ActionView/Erubi outside Rails如何在 Rails 之外使用 ActionView/Erubi
【发布时间】:2019-07-19 20:12:53
【问题描述】:

我经常将 Sinatra 用于小型项目。这对我需要的东西来说非常好,但我错过了将字符串标记为 HTML 安全的能力,然后 ERB 知道何时相应地转义或不转义。

如果我能撕掉 Rails 为 Erubi (around here) 制作的补丁,然后我自己将这些补丁应用到 Erubi,我真的很高兴,这样倾斜就可以使用猴子补丁的 Erubi,每个人都过上幸福的生活后。然而,在挖掘了源代码之后,我不清楚我如何才能真正做到这一点。

我还试图找到一些方法来获取 ActionView 的接口,例如 render 方法,但我什至找不到它的定义位置。

我如何在 Rails 之外使用 ActionView,理想情况下是通过对 Erubi 使用 ActionView 的猴子补丁,或者如果这不起作用,我还能如何使用 ActionView 从模板字符串转到 Rails 之外的渲染字符串?

具体来说,我希望能够做到以下几点:

def some_wrapper_func(unescaped_html)
  "<div>#{h unescaped_html}</div>".html_safe
end

# test1.erb
hello world <%= "<script>alert('hi');</script>" %> <%= some_wrapper_func("<span>foobar</span>") %>
#=> hello world &lt;script&gt;alert(&#x27;hi&#x27;);&lt;&#x2F;script&gt; <div>&lt;span&gt;foobar&lt;&#x2F;span&gt;</div>

【问题讨论】:

    标签: ruby sinatra actionview tilt


    【解决方案1】:

    您需要的是 ActiveSupport。我不确定这是否矫枉过正,但你可以这样做:

    #app.rb:
    require 'sinatra'
    require 'active_support/all'
    
    get '/' do
     erb :index
    end
    

    在一个视图中:

    #views/index.erb
    
    Hello, world!
    <%= "<script>alert('Hello!')</script>".html_safe %>
    

    注意requre 'active_support' 不会加载任何内容,requre 'active_support' 将加载所有模块。您可以按照说明指定需要哪些模块 在Active Support Core Extensions


    如果唯一的目标是启用自动转义,则根本不需要 ActionView。可以这样完成(注意&lt;%== %&gt; 标签):

    #app.rb
    require 'sinatra'
    require 'erubis'
    
    set :erb, :escape_html => true
    
    get '/' do
     erb :index
    end
    
     #View
     <%= "<script>alert('Hello, and it will not produce alert!')</script>" %>
     <%== "<script>alert('Hello and it will!')</script>" %>
    

    我们将尝试让 ActionView 与 Sinatra(或任何 Ruby 程序)一起运行:

    require 'sinatra'
    require 'action_view'
    
    get '/' do
      av_render :index
    end
    
    def av_render view
      paths = ActionView::PathSet.new(["views"])
      lookup_context = ActionView::LookupContext.new(paths)
      renderer = ActionView::Renderer.new(lookup_context)
      view_context = ActionView::Base.new(renderer)
      renderer.render(view_context, template: view)
    end
    

    在视图中我们使用html_safe:

    <%=  "<script>alert('Hello, and it will not produce alert!')</script>" %>
    <%=  "<script>alert('Hello and it will!')</script>".html_safe %>
    

    包装函数也适用于这种方法。这里唯一的问题是自定义渲染方法,但可以避免。

    【讨论】:

    • 您说得对,该代码将运行并工作,但如果您不使用html_safe,它也不会转义,因此&lt;%= "&lt;script&gt;alert('Hello!')&lt;/script&gt;" %&gt; 仍会发送警报。我正在寻找自动转义的非安全字符串,就像在 ActionView 中发生的那样。
    • 我也知道通过 &lt;%== %&gt; 自动转义,但我希望能够将字符串标记为安全或不安全,例如,如果我写一个 nav_element_helper 我希望它能够安全地返回 HTML,但如果我只是做&lt;%= "some string" %&gt;,它会自动转义,类似于 ActionView 的做法。
    • @thesecretmaster 这是我对这个问题的最后一击,请查看基于 ActionView 渲染的解决方案。
    • 谢谢!这似乎正是我所需要的!
    • 与其添加“编辑”或“更新”标签,只需将您的修改添加到您原本包含它们的位置即可。如果需要,我们可以查看是否有任何更改。请记住,SO 就像一本在线百科全书,可读性和语法非常重要,因为您正在为该书中的条目编写解决方案。 “编辑”和“更新”只会降低可读性。
    【解决方案2】:

    如果您想完全避免 ActionView 而只使用 Tilt+Erubi,您实际上可以为自己创建一个 SafeString 类并让 Erubi 使用它进行编译。

    Erubi 有一些重要的选项,具体来说: - escape:如果这是真的,那么&lt;%= %&gt;会默认转义,否则只有&lt;%== %&gt;会默认转义 - bufval:在内部,erubi 使用基本上是一个累加器的东西来构建你的模板。这是它将将该累加器初始化为的值。重要的是它有一个 &lt;&lt;(str) 方法来连接新片段,以及一个 to_s 方法来获取返回值。 - escapefunc:Erubi 将用于转义的函数。覆盖这一点很重要,因为我们希望转义任何不是 SafeString 的东西,但让 SafeStrings 原封不动地通过。

    所以,首先让我们定义这个SafeString 类:

    # main.rb
    require 'tilt'
    require 'erubi'
    
    class SafeString
      def initialize(str = '')
        @str = str
      end
    
      def <<(str)
        if str.is_a? String
          return (@str << str)
        elsif str.is_a? SafeString
          @str = @str << str
          return self
        else
          throw "Can't concat"
        end
      end
    
      def to_s
        @str
      end
    
      def self.escape(val)
        if val.is_a? SafeString
          return val.to_s
        else
          return Erubi.h(val.to_s)
        end
      end
    
      module Helpers
        def raw(content)
          SafeString.new(content)
        end
      end
    end
    

    然后,我们需要包含我们定义的 raw 帮助器并在 ERB 文件上对其进行测试:

    include SafeString::Helpers
    puts Tilt::ErubiTemplate.new("somefile.erb", bufval: 'SafeString.new', escapefunc: 'SafeString.escape', escape: true).render
    
    # somefile.erb
    <%=  "<script>alert('Hello, and it will not produce alert!')</script>" %>
    <%=  raw("<script>alert('Hello and it will!')</script>") %>
    

    这将为我们提供我们想要的输出!

    # stdout
    &lt;script&gt;alert(&#39;Hello, and it will not produce alert!&#39;)&lt;/script&gt;
    <script>alert('Hello and it will!')</script>
    

    要改进这一点,您可以使用ActiveSupport::SafeBuffer,而不是这个最小的SafeString 类。

    【讨论】:

      猜你喜欢
      • 2014-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-03
      • 1970-01-01
      • 2015-04-24
      • 1970-01-01
      • 2013-12-06
      相关资源
      最近更新 更多