重构以下代码行

Refactoring following lines of code

- if clean_book_intro_component(:literary_works).present?
  %h2 Other Books Related to #{@book.title}
  %p.fact-text
    = clean_book_intro_component(:literary_works)

上面的代码只调用clean_book_intro_component(:literary_works)一次就可以写出来吗?

实施clean_book_intro_component

def clean_book_intro_component(component)
  sanitize @book.intro.send(component), tags: %w(span b i p a), attributes: %w(id class style href)
end

是的,只需将 clean_book_intro_component(:literary_works) 的结果保存在一个变量中,然后使用该变量而不是调用该函数。

通常不建议在视图中分配变量。但是,在这种情况下,您可以使用普遍接受的内联赋值(只要您将使用范围限制在条件块的上下文中):

if (intro = clean_book_intro_component(:literary_works)).present?
  %h2 Other Books Related to #{@book.title}
  %p.fact-text
    = intro

另一种解决方案是在函数内部记忆值。

def clean_book_intro_component(component)
  @component ||= {}
  @component[component] ||= sanitize @book.intro.send(component), tags: %w(span b i p a), attributes: %w(id class style href)
end

但是,只要存在对实例的引用,这将导致解释器保留数据。因此,仅在执行成本高昂的非常特殊的情况下才建议这样做 and/or 要记忆的数据有限。

此外,如果助手接受参数,则需要一些额外的复杂性。事实上,您最终会记住与可能的参数输入成线性关系的数据量。

您可以将视图移动到局部视图中并在集合上调用局部视图。如果集合为空,则不会呈现任何内容。类似于:

# a related_books partial
%h2 Other Books Related to #{@book.title}
  %p.fact-text
    = related_books


# in the calling view
= render partial: related_books, collection: [clean_book_intro_component(:literary_works)]

请参阅有关 rendering collections 的 Rails 指南。

- clean_book_intro_component(:literary_works).tap do |cbic|
  - if cbic.present?
    %h2 Other Books Related to #{@book.title}
    %p.fact-text
      = cbic

也许我弄错了 haml,但我的想法是使用 tap 而不是显式保存调用结果