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

时间:2010-03-23 21:41:17

标签: ruby-on-rails ruby partial actionview

例如,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,更改渲染:部分到 &lt;%= render:partial =&gt; 'partial',:locals =&gt; {:dad =&gt; @dad,:son =&gt; a_son}%&gt;,由于某种原因,将一堆变量传递给我的部分让我感到不舒服。也许其他人也有这种感觉。

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

4 个答案:

答案 0 :(得分:103)

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

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

你可以这样做。

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

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

至于是否可以在partials中使用实例变量。我觉得是这样的。实际上,缺点是什么?当然,如果你不一致,事情可能会失控,但我喜欢应用这些指导原则。

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

  2. 如果部分名称与资源名称相同,请将其作为带有<%= render @item %>的本地名称传递。

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

  4. 无论如何,这对我有用。

    奖金提示:如果您发现自己将很多本地人传入某个部分,并且您希望其中一些是可选的,请创建一个辅助方法来渲染部分。然后总是通过辅助方法,这样你就可以使用可选的args创建一个干净的界面来渲染部分。

答案 1 :(得分:42)

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

在partials中使用实例变量有效,但如果需要更改,它可能会使维护应用程序变得更加困难。

在partials中使用实例变量的缺点是你在partial中创建了一个依赖于partial的范围之外的东西(耦合)。这使得部分难以重用,并且当您想要在一个部分中进行更改时,可以强制更改应用程序的多个部分。

使用实例变量的部分:

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

而是将locals传递给partials:

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

现在,因为部分仅引用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) %>

始终?

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

因此,这具有良好的通用性,同时具有相对较低的成本。

答案 2 :(得分:5)

你可以两种方式。在你的部分的顶部:

<% item ||= @item %>

这样,它可以在传递或不传递局部变量的情况下工作,提供合理的默认值,但不会禁止部分的替代使用。

答案 3 :(得分:3)

我投票支持a)因为一个非常具体的原因 - 干!如果你开始传递一个变量 - 就像那样 - 你知道的下一件事 - 它是一团糟 - 让我们说你需要改变你的变量的命名方式或其他的东西 - 然后你需要去你的所有观点并改变它们而不是一个部分。另外 - 如果你改变你的部分 - 让我们说它产生一个带有一些结果的表,它会改变你的所有视图,所以你需要知道使用了哪些视图,一个合适的IDE应该能够帮助你,但我也喜欢在视图的顶部有一个小注释部分 - 我只是提到它的使用位置和原因 - 帮助另一个程序员,它可以帮助你记住,以防你需要回到局部并进行修改。但是部分的全部意义是调用它而不必从视图中传递任何东西,因此如果该变量以某种方式改变,则不必修改调用partial的所有位置。

最终这是一个设计选择 - 说实话,除非你在运行Facebook,否则你做的额外查询并不是什么大不了的事,但它不是很干。

P.S。:想到这一点 - 你实际上可以抽象出你在辅助方法中调用partial的方式,那么如果你调用partial的方式需要改变 - 那么你只需要修改一个地方。