Rails:重构,观点,帮助:这一切是如何结合在一起的?

时间:2010-02-03 19:18:03

标签: ruby-on-rails refactoring views helper

警告:Noob在这里。

我知道这是一个微不足道的主题,但我很难弄清楚如何通过将他们的部分内容转化为帮助来简化我的观点。例如,我总是读到你的视图中的条件是提取帮助器的主要候选者,但是我无法找到这样的例子,而我实现这一目标的尝试失败了。

例如,假设我有:

#index.html.erb

<% for beast in @beasts do -%>
  <% if beast.dead? -%>
    <%= beast.body %>
    <%= link_to "bury", bury_beast_path( :id => beast.id ) %>
  <% else -%>
    <%= beast.body %>
    <%= link_to "kill!", kill_beast_path( :id => beast.id ) %>
  <% end -%>
<% end -%>

在我看来,这让我有点恼火,但我怎么能把这个转移到助手呢?如果可能的话,进一步简化它。 (我已经读过某个条件很糟糕的地方但是如果没有它们你可以编程任何事情就超出了我的范围。)

另一个例子:我需要id我的body代码,格式为controller_action。到目前为止我得到的最好的是:

#index.html.erb

<body id="<%= controller_action %>">

...和...

#application_helper.rb

def controller_action
  @id = @controller.controller_name + "_" + @controller.action_name
end

我不是专家,但即使对我来说,这仍然是丑陋的。

为了使事情变得更复杂,Ryan Singer said something I liked:将ERB视为图像标记,使用帮助程序“揭示意图”。然后在下一次呼吸说你应该没有助手的HTML,这是地狱的方式。 WTF?两者如何兼容?如果它可以在视图中声明行为,那么肯定应该在幕后呈现大量的HTML吗?我无法理解。

所以,基本上就是这样。我很感激,如果有人可以分享一些关于这方面的想法,或者指出我对这个主题进行一些深入的阅读 - 我发现它在网络上的覆盖率非常低。我已经用谷歌搜索了它,但谁知道呢。

4 个答案:

答案 0 :(得分:26)

重构使您的视图更易于维护。问题是选择重构代码的位置。

您的两个选择是部分帮助。没有石头规则规定应该在哪里使用。有一些指南浮出水面,就像一个指出帮助者不应该包含HTML。

一般来说,partials更适合重构比ruby更多HTML / ERB / HAML的部分。另一方面,帮助程序用于使用最少HTML的ruby代码块或从参数生成简单的HTML。

但是,我不同意帮助者根本不应包含HTML的观点。有点可以,只是不要过度。处理帮助程序的方式阻碍了它们用于生成大量HTML。这就是为什么建议您的助手包含最少量的HTML。如果你看看源代码附带的帮助程序,你会注意到它们中的大多数生成了html。少数没有,主要用于生成参数和评估常见条件。

例如,任何表单助手或link_to变体都适合第一种形式的助手。虽然像url_for和logged_in这样的东西?由各种认证模型提供的是第二种。

这是我用来确定是否将视图中的代码分解为部分或帮助的决策链。

  1. 重复或几乎相同的语句产生一个浅的html标签? =&GT;帮手。
  2. 常用表达式用作另一个助手的参数? =&GT;帮手。
  3. 长表达式(超过4个术语)用作另一个助手的参数? =&GT;帮手。
  4. 4条或更多条红宝石(未评估为HTML)? =&GT;帮手。
  5. 几乎所有其他东西=&gt;部分。
  6. 我将使用你想要重构的代码作为例子:

    我会以这种方式重构问题中的观点:

    应用程序/助手/ beast_helper.rb:

    def beast_action(beast)
      if beast.dead?
        link_to "bury", bury_beast_path(beast)
      else
        link_to "kill!", kill_beast_path(beast)
      end
    end
    

    应用程序/视图/兽/ _beast.html.erb:

    <%= beast.body %>
    <%= beast_action(beast) %>
    

    应用程序/视图/兽/ index.html.erb:

    <%= render :partial => "beast", :collection => @beasts %>
    

    技术上更复杂,因为它是3个文件,总共10行而不是1个文件和10行。这些视图现在只有3行,分布在2个文件中。最终结果是您的代码更加干燥。允许您在其他控制器/操作/视图中重用部分或全部部分,而且复杂性最小。

    至于你的身体标签id。你应该真的使用content_for / yield。对于那种事情。

    应用程序/视图/布局/ application.html.erb

    ...
    <body id="<%= yield(:body_id) %>">
    ...
    

    应用程序/视图/兽/ index.html.erb

    <% content_for :body_id, controller_action %>
    ...
    

    这将允许您在任何需要它的视图中覆盖正文的id。例如:

    应用程序/视图/用户/ preferences.html.erb

    <% content_for :body_id, "my_preferences" %>
    

答案 1 :(得分:8)

我要做的第一件事就是:

#index.html.erb
<%= render @beasts %>

#_beast.html.erb
<%= beast.body %>
<%= link_to_next_beast_action(beast) %>    

#beast_helper.rb
def link_to_next_beast_action(beast)
  if beast.dead?
    link_to "bury", bury_beast_path( :id => beast.id ) 
  else
    link_to "kill!", kill_beast_path( :id => beast.id )
  end
end

我所做的是将野兽的渲染分成使用集合语义的部分。

然后我将用于显示杀戮/埋葬链接的逻辑移动到野兽助手中。这样,如果你决定添加另一个动作(例如,'从死亡中恢复'),你只需要改变你的助手。

这有帮助吗?

答案 2 :(得分:1)

第三种选择是使用Cells gem中的视图模型。这是一个非常流行的框架,它将面向对象引入Rails中的视图层。

# app/cells/beast/cell.rb

class Beast::Cell < Cell::Concept
  def show
    return dead if model.dead?
    kill
  end

private
  def dead
    link_to "bury", bury_beast_path( :id => model.id ) 
    # you could render a view here, too!
  end

  def kill
    link_to "kill!", kill_beast_path( :id => model.id )
  end
end

然后使用帮助器(在视图或控制器中)渲染视图模型。

# app/views/beasts/index.erb

<%= concept(:beast, @beast).call %>
<%-# this returns the link content %>

这就是全部!您可以在单独的测试中测试此单元格。单元格还为您提供视图渲染,视图继承等等。

例如,您可以使用kill链接的视图。

# app/cells/beast/cell.rb

class Beast::Cell < Cell::Concept

  # ..

  def kill
    render :kill
  end
end

这会渲染单元格的杀手视图。

# app/cells/beast/views/index.erb

<%= link_to "kill!", kill_beast_path( :id => model.id ) %>

请注意视图的位置,它很好地打包到单元目录中。

而且,是的,单元格可以执行HAML以及AbstractController支持的任何其他模板引擎。

答案 3 :(得分:0)

另一个策略是根本不使用模板和助手。 为了渲染你可以:

  1. 使用render(:inline =&gt;)直接从控制器渲染视图。如果您仍希望将视图和控制器正式分开,则可以创建包含在控制器中的模块/混合。
  2. 或创建自己的视图类并使用它们来呈现您的响应。
  3. 这背后的想法是帮助者和rails erb模板系统不利用OOP,因此在一天结束时,您无法根据每个控制器/请求的需要定义您将专门化的一般行为;通常情况下,最终会重写非常相似的代码块,从维护的角度来看,这不是很好。

    然后,如果你仍然需要一些辅助方法(例如form_tag,h,raw,...),你只需要将它们包含在你的控制器/专用视图类中。

    请参阅:rails-misapprehensions-helpers-are-shit了解有趣但有用的文章。

    编辑:听起来不像是一个完整的冲洗,我说实现这取决于你的应用程序应该有多大,以及你需要多久更新一次代码。另外,如果您将设计委托给非程序员,他/她可能会在深入研究您的代码之前参加一些编程课程,而这些课程无疑可以直接理解为模板语法。