Rails:分部应该知道实例变量吗?


67

例如,瑞安·贝茨(Ryan Bates)的nifty_scaffolding

edit.html.erb

<%= render :partial => 'form' %>

new.html.erb

<%= render :partial => 'form' %>

_form.html.erb

<%= form_for @some_object_defined_in_action %>

这种隐藏状态使我感到不舒服,所以我通常喜欢这样做

edit.html.erb

<%= render :partial => 'form', :locals => { :object => @my_object } %>

_form.html.erb

<%= form_for object %>

那么哪个更好:a)使局部变量访问实例变量,或者b)传递局部变量所需的所有变量?

到目前为止,我一直在选择b),但确实遇到了一些泡菜:

some_action.html.erb

<% @dad.sons.each do |a_son| %>
<%= render :partial => 'partial', :locals => { :son => a_son } %>
<% end %>

_partial.html.erb

The son's name is <%= son.name %>
The dad's name is <%= son.dad.name %>

son.dad进行数据库调用以获取爸爸!因此,我要么必须访问@dad,否则它将返回到a)具有局部访问实例变量,或者我必须在本地变量中传递@dad,将render:partial更改为<%= render:partial =>'partial' ,:locals => {::dad => @dad,:son => a_son}%>,由于某种原因,将一堆var传递给我的局部对象使我感到不舒服。也许其他人也有这种感觉。

希望这是有道理的。寻找一些关于这件事的见解...谢谢!


我尝试对我的大部分局部参数进行参数化,因为@vars方式像全局vars一样下降,并且伴随着它们的所有错误,但是有人也使用@vars方式,无论您的应用程序
是否

克莱夫(Clyfe)为什么觉得自己像全球人?它们的作用域在您的控制器中。而且,除了阅读和显示它们之外,您不应在视图或局部视图中对它们进行任何处理。即使采用表单-您正在做的事情就是接受输入-所有设置都是在创建或更新操作中完成的。
konung

Answers:


106

在最新版本的Rails中,渲染局部并将局部变量传递给它们要容易得多。代替这个。

<%= render :partial => 'form', :locals => { :item => @item } %>

你可以这样做。

<%= render 'form', :item => @item %>

我不会在Nifty Scaffold生成器中执行此操作以保持向后兼容性,但我将在以后的版本中对此进行更改。

至于在局部变量中使用实例变量是否可以接受。我觉得是这样的。实际上,不利之处是什么?当然,如果不一致,事情可能会失控,但是我喜欢应用这些准则。

  1. 切勿创建仅在部分之间共享实例变量的实例变量。通常这意味着您将只共享控制器资源对象。

  2. 如果partial与资源同名,则使用将该资源作为本地传递<%= render @item %>

  3. 如果部分内容将在多个控制器之间共享,则仅使用本地。

无论如何,这对我来说很有效。

温馨提示:如果您发现自己将很多局部变量传递给局部变量,并且希望其中的一些局部变量是可选的,请创建一个帮助程序方法来呈现局部变量。然后,请始终通过helper方法,以便您可以使用可选的args创建一个干净的接口来呈现部分代码。


4
+1表示“3。如果部分控制器将在多个控制器之间共享,则只能使用本地控制器。”
dubilla

ew表示新语法。太am昧了。
ahnbizcad '16

46

在局部函数中使用@instance_variables是错误的设计。

在局部函数中使用实例变量是可行的,但是如果需要更改,则可能会使维护应用程序变得更加困难。

在局部变量中使用实例变量的缺点是,您在局部变量中创建了对局部变量范围(耦合)之外的内容的依赖。这使得部分代码难以重用,并且当您要更改一个部分时,可以在应用程序的多个部分中进行更改。

使用实例变量的部分:

  • 当使用部分控制器的任何控制器中的实例变量更改实例变量名称或其类型或数据结构时,必须更改
  • 当实例变量的使用方式发生更改时,导致所有使用该局部操作的控制器操作以相同的方式同时更改
  • 不鼓励重用,因为它们只能在使用相同名称和数据设置实例变量的操作中轻松重用

而是将局部变量传递给局部变量:

<%= render 'reusable_partial', :item => @item %>

现在,由于partial仅引用了item而不是not @item,因此可以自由更改渲染呈现reusable_partial的视图的操作,而不会影响reusable_partial和其他渲染该操作的视图/视图:

<%= render 'reusable_partial', :item => @other_object.item %>

另外,可以在没有@item的上下文中重用此方法:

<%= render 'reusable_partial', :item => @duck %>

如果我@duck将来进行更改并且不再像reusable_partial期望的那样杂乱无章(对象的接口发生更改),我还可以使用适配器来传递reusable_partial期望的项目类型:

<%= render 'reusable_partial', :item => itemlike_duck(@duck) %>

总是?

在很多情况下,您可能不需要像这样的去耦部分,并且在短期内使用实例变量会更容易。但是,很难预测应用程序的未来需求。

这样,这使得良好的通用实践同时具有相对较低的成本。


完全同意您@nilbus。处理部分可重复使用的部分时感觉相同
魔术师

“但是,很难预测应用程序的未来需求。” ->因此,我会在需要时添加本地语言,而不是过早地对此进行优化。令人高兴的是,除了更少的代码(故障点)之外,当您看到本地传递到局部时,您立即知道它也被其他控制器使用。
Magne

1
我还要指出,使用实例变量而不是传递局部变量更是依靠约定而不是配置的方法。当局部变量仅由同一控制器使用时指定局部变量(顺便说一句,实例变量应只设置一个位置:在常见的before_action方法中),表示不必要的配置/特性。
Magne

3

您可以同时使用。在部分内容的顶部:

<% item ||= @item %>

这样,无论是否传递局部变量,它都可以工作,提供了合理的默认值,但不禁止局部变量的替代用法。


3
这使得耦合完全不清楚。现在,Partial有两个合同。
Derek 2015年

1

我投票给a)是出于非常具体的原因-干!如果您开始传递这样的变量,那么接下来您就会知道这是一团糟。假设您需要更改变量的命名方式或其他方式。您需要转到所有视图并更改它们,而不是局部视图。

另外,如果更改部分视图,则所有视图都会更改,因此您需要知道使用了哪些视图。适当的IDE应该可以为您提供帮助,但是我也喜欢在视图顶部有一个小的注释部分,我只在其中提及使用位置以及原因。这可以帮助其他程序员,并且可以帮助您记住是否需要重新编写部分内容并进行修改。但是,partial的全部要点是调用它,而不必传递视图中的任何内容,因此,如果该变量以某种方式更改,则不必修改从中调用partial的所有位置。

归根结底,这是一种设计选择,说实话,除非您正在运行Facebook,否则您所做的额外查找并不是一件大事,但它不是很干。

PS:只是考虑一下。实际上,您可以在一个辅助方法中抽象您调用部分函数的方式,因此,如果您需要更改部分函数的调用方式,则只需要修改一个位置即可。


3
当某些东西不是DRY时,仍然不是在代码中遍布全局变量的原因。否则,所有功能将变为无参数。
RocketR 2011年

所以我们知道该怎么办。不要在局部到局部之间传递局部变量。不要使用全局变量。因此,一个好的实践解决方案将是...助手?
ahnbizcad '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.