67

例如,Ryan Bates 的 nifty_scaffolding 就是这样做的

编辑.html.erb

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

新的.html.erb

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

_form.html.erb

<%= form_for @some_object_defined_in_action %>

那种隐藏的状态让我感觉不舒服,所以我通常喜欢这样做

编辑.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)有partials访问实例变量,或者我必须在locals中传递@dad,将render :partial更改为<%= render :partial => 'partial' , :locals => { :dad => @dad, :son => a_son } %>,并且由于某种原因将一堆 vars 传递给我的部分让我感到不舒服。也许其他人也有这种感觉。

希望这有点道理。寻找对整个事情的一些见解......谢谢!

4

4 回答 4

107

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

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

你可以这样做。

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

我不会在 Nifty Scaffold 生成器中这样做以保持向后兼容性,但我会在未来的版本中更改它。

至于在partials中使用实例变量是否可以接受。我认为是这样。在所有实用性方面,有什么缺点?当然,如果您不一致,事情可能会失控,但我喜欢应用这些准则。

  1. 永远不要创建实例变量只是为了在部分之间共享它。通常这意味着您将只共享控制器资源对象。

  2. 如果部分与资源同名,则将其作为本地传递给<%= render @item %>.

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

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

额外提示:如果您发现自己将很多本地变量传递给局部变量,并且您希望其中一些是可选的,请创建一个渲染局部变量的辅助方法。然后总是通过辅助方法,以便您可以使用可选参数制作一个干净的界面来呈现部分。

于 2010-03-23T22:42:19.100 回答
47

在部分中使用 @instance_variables 是糟糕的设计。

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

在部分中使用实例变量的缺点是您在部分中创建了对部分范围之外的事物的依赖关系(耦合)。这使得部分更难重用,并且当您想要对一个部分进行更改时,可能会强制更改应用程序的多个部分。

使用实例变量的部分:

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

相反,将局部变量传递给局部变量:

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

现在,因为 partial 只引用item而不是@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) %>

总是?

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

因此,这有助于良好的一般实践,同时具有相对较低的成本。

于 2012-12-06T20:41:29.270 回答
3

你可以同时拥有它。在您的部分顶部:

<% item ||= @item %>

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

于 2013-10-09T02:11:42.563 回答
1

我投票支持 a) 有一个非常具体的原因——DRY!如果你开始传递一个这样的变量,接下来你就会知道它是一团糟。假设您需要更改变量的命名方式或其他相关内容。您需要转到所有视图并更改它们而不是一个部分。

此外,如果您更改部分视图,它会更改所有视图,因此您需要知道使用了哪些视图。一个合适的 IDE 应该能够帮助您解决这个问题,但我也喜欢在视图顶部有一个小的注释部分,我只提到它的使用位置和原因。这有助于另一个程序员,它可以帮助你记住,以防你需要回到部分和修改。但是 partial 的全部意义在于调用它而不必从视图中传递任何东西,这样如果该变量以某种方式发生变化,您就不必修改调用 partial 的所有位置。

最终这是一个设计选择,老实说,除非您正在运行 facebook,否则您所做的额外查找并不是什么大不了的事,但它并不是很干燥。

PS:刚想好。您实际上可以抽象出您在辅助方法中调用部分的方式,因此如果您调用部分的方式需要更改,您只需要修改一个地方。

于 2010-03-23T22:21:59.477 回答