17

警告:这里是菜鸟。

我知道这是一个微不足道的主题,但我很难弄清楚如何通过将部分视图移入助手来简化我的视图。例如,我一直读到您观点中的条件是提取到帮助程序中的主要候选者,但我真的找不到这方面的例子,而且我实现这一目标的尝试失败了。

例如,假设我有:

#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 %>">

……和……</p>

#application_helper.rb

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

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

为了让事情变得更复杂,Ryan Singer 说了我喜欢的话:将 ERB 视为图像标签,使用助手“揭示意图”。然后在接下来的呼吸中说你不应该在帮助程序中使用 HTML,因为那是通往地狱的道路。怎么回事?两者如何兼容?如果到了可以只在视图中声明行为的地步,那么肯定应该有很多 HTML 需要在幕后渲染吗?我无法掌握。

所以,基本上就是这样。如果有人能就此分享一些想法,或者指出我对这个主题的一些很好的深入阅读,我将不胜感激——我发现它在网络上的报道非常薄弱。我已经用谷歌搜索了它,但谁知道呢。

4

4 回答 4

27

重构使您的视图更易于维护。问题在于选择重构代码的去向。

您的两个选择是partialshelpers。没有一成不变的规则规定应该在哪里使用。有几条准则漂浮在各处,例如声明助手不应包含 HTML 的准则。

通常,partials 更适合重构 HTML/ERB/H​​AML 而非 ruby​​ 的部分。另一方面,帮助程序用于具有最少 HTML 的 ruby​​ 代码块或从参数生成简单的 HTML。

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

例如,任何形式的帮助程序或 link_to 变体都适合第一种形式的帮助程序。而像url_for和logged_in这样的东西?由各种身份验证模型提供的属于第二种。

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

  1. 重复或几乎相同的语句产生单个浅 html 标记?=> 帮手。
  2. 用作另一个助手的参数的常用表达式?=> 帮手。
  3. 用作另一个助手的参数的长表达式(超过 4 个术语)?=> 帮手。
  4. 4 行或更多行 ruby​​(未评估为 HTML)?=> 帮手。
  5. 几乎所有其他东西=>部分。

我将以您要重构的代码为例:

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

应用程序/帮助者/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

应用程序/views/beasts/_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 %>
...

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

app/views/users/preferences.html.erb

<% content_for :body_id, "my_preferences" %>
于 2010-02-03T20:54:58.273 回答
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

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

然后,我将显示杀死/埋葬链接的逻辑移到了野兽助手中。这样,如果您决定添加另一个动作(例如,'bring back from dead'),您只需更改您的助手。

这有帮助吗?

于 2010-02-03T20:36:59.653 回答
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.

于 2014-06-23T23:10:43.917 回答
0

另一个策略是根本不使用模板和助手。对于渲染,您可以:

  1. 使用 render(:inline => ) 直接从控制器渲染视图。如果您仍想保持视图和控制器正式分离,您可以创建包含在控制器中的模块/混合。
  2. 或创建您自己的视图类并使用它们来呈现您的响应。

这背后的想法是 helpers 和 rails erb 模板系统不利用 OOP,因此最终您无法定义您将根据每个控制器/请求的需求专门化的一般行为;通常情况下,最终会重写看起来非常相似的代码块,从维护的角度来看,这并不是很好。

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

请参阅:rails-misapprehensions-helpers-are-shit以获得有趣但有用的文章。

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

于 2013-06-10T18:50:18.617 回答