如何在Rails之外使用ActionView / Erubi

时间:2019-07-19 20:12:53

标签: ruby sinatra actionview tilt

我经常将Sinatra用于小型项目。可以满足我的需要,但是我错过了将字符串标记为HTML安全的功能,然后ERB知道何时进行相应的转义或不进行转义的功能。

如果我可以拆下Rails制作给Erubi(around here)的补丁,然后自己将这些补丁应用到Erubi,这样倾斜就可以使用猴子补丁的Erubi,而每个人都可以住,我真的很喜欢从此以后快乐地生活着。但是,在深入研究源代码之后,我不清楚我如何才能真正做到这一点。

我还试图找到某种方法来使接口进入ActionView,例如render方法,但我什至找不到定义的位置。

如何在Rails之外使用ActionView,理想情况下是通过使用ActionView的猴子补丁到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>

2 个答案:

答案 0 :(得分:2)

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

#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。可以这样做(注意<%== %>标签):

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

包装器功能也可以使用这种方法。唯一的问题是自定义渲染方法,但可以避免。

答案 1 :(得分:0)

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

Erubi有一些重要的选择,特别是:   -escape:如果为true,则默认情况下<%= %>将转义,否则默认情况下仅<%== %>将转义   -bufval:在内部,erubi基本上使用累加器来构建模板。这是它将累加器初始化为的值。重要的是,它具有一个<<(str)方法来连接新片段,以及一个to_s方法来获取返回值。   -escapefunc:Erubi将用于转义的功能。覆盖这一点很重要,因为我们要转义不是SafeString的所有内容,而是让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帮助程序,并在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类。

相关问题