我同意逻辑不应该在控制器中,但让我们更具体地了解你将如何实现它。
首先,您将模板存储在数据库中的什么位置?它们应该存储在自己的模型中,让我们调用它
CustomerTemplate
并赋予属性:Text 类型的模板。
所以现在我们有两种类型的对象,Customers 和 CustomerTemplates。如何在给定模板的情况下呈现客户?老实说,在 CustomerTemplate 模型中拥有一个接收客户并呈现它的函数并不可怕render
,但它在你的应用程序中放置了一些严格来说不属于那里的逻辑。您应该将“客户特定的渲染逻辑”与“渲染我的简单自定义模板语言”分开。
因此,让我们为您的自定义语言创建一个简单的模板处理程序,我将给它取个昵称Curly。这个处理程序应该对客户一无所知。它所做的只是接受一个字符串并在 {} 中插入值。这样,如果您想在将来添加新的模板类型——比如说,渲染另一个模型,比如发票——你可以使用相同的模板类型。
Rails 中的模板是响应call
并注册到ActionView::Template的类。最简单的例子是Builder。
这是一个快速编写的模板处理程序,它呈现卷曲。该
call
函数返回一个经过 eval 的字符串,因此该字符串必须是有效的 ruby 代码。字符串 eval 在渲染调用的范围内,因此它可以访问通过{ locals: {} }
渲染选项传入的任何变量。
# In lib/curly_template_handler.rb
class CurlyTemplateHandler
def self.call(template)
src = template.source
"""
r = '#{src}'.gsub(/{([^}]*)}/) { |s|
local_assigns[$1.to_sym] || s
}
raw r
"""
end
end
确保处理程序已初始化,让我们将其设置为侦听 :curly 类型。
# In config/initializers/register_curly_template.rb
ActionView::Template.register_template_handler(:curly, CurlyTemplateHandler)
我们需要将 lib/ 添加到 autoload_paths 以便加载类:
# config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
最后,我们可以在视图中渲染我们的模板!我在这里嵌入了字符串,但你真的会从一个CustomerTemplate
对象中得到它:
<%= render(inline: "<h2>{customer_name}</h2><p>{customer_address}</p>",
type: :curly,
locals: { customer_name: @customer.name,
customer_address: @customer.address }) %>
不要在生产中使用我的示例代码!我遗漏了一堆你需要处理的极端情况,比如清理用户输入。