如何在 Rails 之外使用 ActionView/Erubi



我经常在小型项目中使用Sinatra。它非常适合我需要的东西,但我错过了将字符串标记为 HTML 安全的能力,然后 ERB 知道何时转义或不转义。

如果我能撕掉 Rails 对 Erubi 制作的补丁(在这里),然后自己将这些补丁应用于 Erubi,这样 tilt 就可以使用猴子补丁的 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>

这里你需要的是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'将加载所有模块。您可以指定需要哪些模块,如前所述 在活动支持核心扩展中。


如果唯一目标是启用自动转义,则根本不需要 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 %>

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

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

Erubi 采取了一些重要的选择,特别是: -escape:如果这是真的,那么<%= %>默认会转义,否则只有<%== %>会默认转义 -bufval:在内部,erubi 使用基本上是一个累加器来构建你的模板。这是它将累加器初始化为的值。重要的是,它有一个<<(str)方法来连接新部分,以及一个to_s方法来获取返回值。 -escapefunc:Erubi 将用于转义的功能。重写这一点很重要,因为我们想要转义任何不是安全字符串的内容,但让安全字符串原封不动地通过。

因此,首先让我们定义这个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类。

相关内容

最新更新