【问题标题】:Can a Rails view specify a content_for array so both view and layout are DRY?Rails 视图可以指定一个 content_for 数组,以便视图和布局都是 DRY 吗?
【发布时间】:2017-02-16 03:36:08
【问题描述】:

背景:由于电子邮件客户端(错误)处理样式的方式,在 Rails 邮件布局中,所有样式都需要为每个标签内联,因此布局很冗长。

因此,例如,如果您有一个信息块,该信息块包含一行中的 3 个段落 (%p),具有相同的样式,则该样式必须应用于五个段落中的每一个。

# example of  hard_coded_mailer_layout.html.haml
...
%p{style: "some very very long style declaration"}
  This sentence is about Foo.
%p{style: "the SAME REPEATED very very long style declaration"}
  This sentence is about Bar.
%p{style: "yes, again, the SAME repeated long style declaration"}
  This sentence is about FooBar.
...

所以现在假设文本是特定于帐户的并且来自视图(而不是硬编码到布局中)。

如果是已知的最大段数(上例中为 3 个),则视图可以简单地指定 3 个 content_for 块(:foo、:bar 和 :foobar)并且布局可以有 3 个相应的产量(:foo、:bar 和 :foobar)如下所示:

# example layout_yielding_3_blocks.html.haml
...
- if content_for?(:foo)
  %p{style: "some very very long style declaration"}
    = yield :foo
- if content_for?(:bar)
  %p{style: "the SAME REPEATED very very long style declaration"}
    = yield :bar
- if content_for?(:foobar)
  %p{style: "yes, again, the SAME repeated long style declaration"}
    = yield :foobar
...

# corresponding view
- content_for :foo do
  Your account has 2 Foos.
- content_for :bar do
  Your account has 8 Bars.
- content_for :foobar do
  Your account has 0 FooBars.
...

问题:如果您想将可变数量的段落传递给布局,但仍然让布局应用样式,该怎么办?有没有办法让视图指定一个包含 N 个 content_for 元素的数组,以便布局可以简单地遍历它们?具体是这样的:

# desired view... is it possible?
- content_for :info[0] do
  Your account has 2 Foos.
- content_for :info[1] do
  Your account has 8 Bars.
- content_for info[2] do
  Your account has 0 FooBars.
...

因此布局可能如下所示:

#  desired corresponding layout, can something like this be done?
...
- yield(:info).each_with_index do |para, i|
  %p{style: "some very very long style declaration"}
    = (yield(:info))[i]

简单但有问题的方法: 简单的做法是在视图中设置一个单个 content_for,其中包含所有 N 个段落,它们的相同样式重复 N 次,像这样:

# current way of doing it (bad for 2 reasons below)
- content_for :all_info do
  %p{style: "some very very long style declaration"}
    Your account has 2 Foos.
  %p{style: "the SAME REPEATED very very long style declaration"}
    Your account has 8 Bars.
  %p{style: "yes, again, the SAME repeated long style declaration"}
    Your account has 0 FooBars.

但是那很臭(就像代码臭味一样)因为(a)它非常不干燥,甚至更糟(b)现在内联样式分布在单个布局和可能使用该布局的数十个视图之间......如果您更改“样式”,则需要在很多地方进行更改,或者在其他地方将样式定义为字符串或在其他地方命名为 email_para_style_info 的常量作为变量。

【问题讨论】:

    标签: ruby-on-rails dry content-for


    【解决方案1】:

    改为构建并使用视图助手。

    module EmailHtmlHelper
      def account_message(content = nil, &block)
        content_tag :p, content, style: account_message_styles, &block
      end
    
      def account_message_styles
        %{
          font-size: 1.2em;
          color: #c0ffee;
        }.tr("\n", '')
      end
    end
    
    <%= account_message 'Your account has 2 Foos.' %>
    
    <%= account_message do %>
      A longer, 
      more complex
      <span>message</span>
      <%= link_to 'here', foo_url %>
    <% end %>
    

    或者,如果您真的不希望在帮助程序中使用样式(在这种情况下这是一个完全可以接受的地方),您只需点按视图中的样式并为每个实例使用它们:

    <% "color: blue;".tap do |inline_styles| %>
      <%= content_tag :p, 'Status: Open', style: inline_styles %>
      <%= content_tag :p, 'Balance: $100', style: inline_styles %>
    <% end %>
    

    请注意,使用 content_tag 之类的标签助手将适当地转义内容,这意味着您可以避免意外关闭引号的问题。

    【讨论】:

    • 这是一种可靠的方法,但如果可能的话,更好的 IMO 将内容和样式完全分离,布局(仅)呈现样式表。这就是我希望有人可以提出的答案。如果可能的话,某种“Iterable content_for”结构将是完美的。
    • @jpwynn 如果您的原始问题有任何迹象,我认为您正在争论 less 分离。在这种情况下,我在更新中为您提供了一个不太优雅的选项。
    猜你喜欢
    • 2011-07-12
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 2011-08-17
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多