代码之家  ›  专栏  ›  技术社区  ›  thesecretmaster azazdeaz

ActionView/Erubi在Rails外部

  •  0
  • thesecretmaster azazdeaz  · 技术社区  · 5 年前

    我经常在小型项目中使用Sinatra。这对于我所需要的内容来说是非常好的,但是我错过了将字符串标记为HTML安全的功能,然后ERB知道何时进行转义或不进行相应的转义。

    如果我能去掉Rails给Erubi做的补丁,我真的很喜欢( around here )然后把这些补丁贴在Erubi上,这样tilt就可以使用猴子补丁Erubi了,从此以后每个人都过上了幸福的生活。然而,在深入研究了源代码之后,我并不清楚我如何才能真正做到这一点。

    我还试图找到一些方法让一个接口进入ActionView,比如 render 方法,但我甚至找不到它的定义。

    如何在Rails之外使用ActionView,理想情况下是使用ActionView的monkey补丁到Erubi,或者如果这不起作用,如何使用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>
    
    0 回复  |  直到 5 年前
        1
  •  2
  •   the Tin Man    5 年前

    你需要的是积极的支持。我不确定这是否是过度杀戮,但你可以这样做:

    #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' 不会装载任何东西 要求“主动支持” 将加载所有模块。您可以按照说明指定需要哪些模块 在里面 Active Support Core Extensions .


    如果唯一的目标是启用自动转义,那么根本不需要ActionView。可以这样做(注意 <%== %> 标签):

    #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>" %>
    

    我们将尝试使用Sinatra(或任何Ruby程序)启动并运行ActionView:

    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 %>
    

    包装函数也可以使用这种方法。这里唯一的问题是自定义呈现方法,但是可以避免。

        2
  •  0
  •   thesecretmaster azazdeaz    5 年前

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

    Erubi采取了一些重要的选择,特别是: - escape :如果这是真的,那么 <%= %> 默认情况下将转义,否则仅 <%== %> 默认情况下将转义 - bufval :在内部,erubi使用基本上是累加器的东西来构建模板。这是它将该累加器初始化为的值。重要的是它有一个 <<(str) 方法来浓缩新的片段,以及 to_s 方法获取返回值。 - escapefunc :Erubi将用于转义的函数。重写这一点很重要,因为我们希望转义任何不是SafeString的内容,但让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 我们定义了helper并在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 .