【问题标题】:How to structure Util classes in RoR如何在 RoR 中构造 Util 类
【发布时间】:2013-07-11 23:01:14
【问题描述】:

我有一个用户可以上传的模板来生成报告。他们可以将特殊标签放入 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>

我有一个控制器来查找客户,然后解析模板并替换令牌。

现在我在控制器中有解析代码,创建了一个胖控制器。不好。

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

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

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3.2


    【解决方案1】:

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

    【讨论】:

    • lib 文件夹是您需要放置它的位置。这不是model 代码,因为您没有将它存储在数据库中。 (lib 的替代方法是创建一个也适合这种情况的 app/services 文件夹)
    • 我假设它会进入客户模型,而不是它自己的模型。类似于: def self.parse(html)
    • 客户模型不是正确的地方。什么更有意义:customer.parse_templatecustomer.address?在客户模型中解析的模板违反了单一职责原则,并且(如前所述)最好将其移动到 servicelib 对象中。
    【解决方案2】:

    我同意逻辑不应该在控制器中,但是让我们得到一个 更具体地说明您将如何实现这一点。

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

    所以现在我们有两种类型的对象,客户和 客户模板。如何在给定模板的情况下呈现客户?它 老实说,只有一个 render 函数不会可怕 CustomerTemplate 模型,它接受一个客户并呈现它,但是 它在您的应用程序中放置了一些不严格属于的逻辑 那里。您应该分离出“客户特定的渲染逻辑” 来自“渲染我的简单自定义模板语言”。

    所以,让我们为您的自定义语言创建一个简单的模板处理程序, 我将给它起个昵称 Curly。这个处理程序应该一无所知 顾客。它所做的只是接受一个字符串并在里面插入值 {} 的。这样,如果您想在将来添加新的模板类型 - 比如说,渲染另一个模型,比如发票——你可以使用相同的 模板类型。

    Rails 中的模板是响应call 的类,并且是 注册ActionView::Template。最简单的例子是Builder

    这是一个快速编写的模板处理程序,它呈现 Curly。这 call 函数返回一个经过评估的字符串,因此该字符串必须 是有效的红宝石代码。由渲染调用限定的字符串 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 }) %>
    

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

    【讨论】:

      猜你喜欢
      • 2012-09-30
      • 2016-08-29
      • 1970-01-01
      • 1970-01-01
      • 2018-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多