Ruby on rails 如何在RoR中构造Util类

Ruby on rails 如何在RoR中构造Util类,ruby-on-rails,ruby,ruby-on-rails-3.2,Ruby On Rails,Ruby,Ruby On Rails 3.2,我有一个模板,用户可以上传生成报告。他们可以将特殊的标记放入html模板中,然后用数据库中的数据替换。快速示例: <div class="customer-info"> <h1>{customer_name}</h1> <h2>{customer_address_line1}</h2> <h2>{customer_address_line2}</h2> <h2>{customer_ad

我有一个模板,用户可以上传生成报告。他们可以将特殊的标记放入html模板中,然后用数据库中的数据替换。快速示例:

<div class="customer-info">
  <h1>{customer_name}</h1>
  <h2>{customer_address_line1}</h2>
  <h2>{customer_address_line2}</h2>
  <h2>{customer_address_city}, {customer_address_state} {customer_address_zip}</h2>
</div>

{客户名称}
{客户\地址\线路1}
{客户\地址\线路2}
{客户地址{城市},{客户地址{州}{客户地址}
我有一个控制器,它查找客户,然后解析模板并替换令牌

现在我在创建fat控制器的控制器中有了解析代码。不太好

但是我应该把代码移到哪里呢?模型文件夹?创建一个Util文件夹并将其放在那里


只是不确定Rails的方式会是什么。

我对此也很好奇,并发现了一个非常类似的讨论。老实说,我认为这取决于有多少解析代码。如果只有很少几行,那么模型就是一个安全的地方。如果它是一个大的包,特别是一个可重用的包,/lib/文件夹可能是解析本身的更好选择。但是,正如您所建议的,您肯定应该将其从控制器中删除

我同意逻辑不应该在控制器中,但是让我们来看看 关于如何实现这一点,请再具体一点

首先,您将模板存储在数据库中的什么位置?他们 应该存储在自己的模型中,我们称之为
CustomerTemplate
并提供一个属性:文本类型的模板

现在我们有两种类型的对象,客户和 客户模板。如何呈现给定模板的客户?信息技术 老实说,在中只使用
render
函数并不可怕 接受客户并对其进行渲染的CustomerTemplate模型,但是 它是在你的应用程序中加入一些逻辑,而这些逻辑并不严格属于你的应用程序 那里您应该分离出“特定于客户的呈现逻辑” 来自“呈现我的简单自定义模板语言”

那么,让我们为您的自定义语言创建一个简单的模板处理程序, 我要给它起个绰号叫“卷发”。这个处理程序不应该知道任何关于 客户。它所做的只是获取一个字符串并在其中插入值 {}的。如果将来要添加新模板类型,请使用这种方法- 比方说,要渲染另一个模型(如发票),可以使用相同的 模板类型

Rails中的模板是响应
调用的类
在……登记。最简单的例子是

下面是一个快速编写的模板处理程序,它可以渲染Curly。这个
call
函数返回一个已求值的字符串,因此该字符串必须 必须是有效的ruby代码。字符串eval的作用域由render调用确定,因此 它可以访问通过
{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
确保处理程序已初始化,然后将其设置为侦听 头发:卷曲型

# In config/initializers/register_curly_template.rb
ActionView::Template.register_template_handler(:curly, CurlyTemplateHandler)
我们需要将lib/添加到自动加载路径,以便加载类:

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

不要在生产中使用我的示例代码我漏掉了一堆角
您需要处理的情况,如清理用户输入。

lib
文件夹是您需要放置它的地方。这不是
model
代码,因为您没有将其存储在数据库中。(lib的另一种选择是创建一个
app/services
文件夹,该文件夹也适用于此场景)我假设它将位于客户模型中,而不是它自己的模型。类似于:def self.parse(html)的东西客户模型不是正确的位置。更有意义的是:
customer.parse_模板
customer.address
?在客户模型中解析的模板违反了单一责任原则,并且(如前所述)最好移动到
服务
对象中。