web-dev-qa-db-ja.com

Rails:パーシャルはインスタンス変数を知っているべきですか?

たとえば、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}%>、そして何らかの理由で私のパーシャルにたくさんの変数を渡すと不快に感じます。多分他の人もこのように感じます。

うまくいけば、それはある程度理にかなっています。この全体についての洞察を探しています...ありがとう!

63
Alexandre

Railsの最近のバージョンでは、パーシャルをレンダリングしてローカルに渡すのはかなり簡単です。これの代わりに。

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

あなたはこれを行うことができます。

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

下位互換性を保つためにNifty Scaffoldジェネレーターでこれを行うことはありませんが、将来のリリースで変更する予定です。

パーシャルでインスタンス変数を使用することが許容されるかどうかに関しては。それはそうですね。すべての実用性において、欠点は何ですか?一貫性がないと物事が手に負えなくなることは確かですが、私はこれらのガイドラインを適用したいと思っています。

  1. パーシャル間で共有するためだけにインスタンス変数を作成しないでください。通常、これはコントローラーリソースオブジェクトのみを共有することを意味します。

  2. パーシャルがリソースと同じ名前の場合は、<%= render @item %>を使用してローカルとして渡します。

  3. パーシャルが複数のコントローラー間で共有される場合は、ローカルのみを使用します。

これはとにかく私にとってうまくいくものです。

ボーナスヒント:多くのローカルをパーシャルに渡していて、それらの一部をオプションにしたい場合は、パーシャルをレンダリングするヘルパーメソッドを作成します。次に、常にヘルパーメソッドを使用して、パーシャルをレンダリングするためのオプションの引数を持つクリーンなインターフェイスを作成できるようにします。

103
ryanb

パーシャルで@instance_variablesを使用するのは悪い設計です。

パーシャルでインスタンス変数を使用すると機能しますが、変更が必要になった場合にアプリケーションを維持するのが難しくなる可能性があります。

パーシャルでインスタンス変数を使用することの欠点は、パーシャルのスコープ外(カップリング)への依存をパーシャルに作成することです。これにより、部分の再利用が困難になり、1つの部分を変更したいときに、アプリケーションの複数の部分を強制的に変更できます。

インスタンス変数を使用するパーシャル:

  • 部分変数を使用するコントローラーのインスタンス変数がインスタンス変数名またはそのタイプまたはデータ構造のいずれかを変更すると、変更する必要があります
  • インスタンス変数の使用方法が変更されたときに、パーシャルを使用するすべてのコントローラーアクションを同時に同じ方法で変更します。
  • 同じ名前とデータでインスタンス変数を設定するアクションでのみ簡単に再利用できるため、再利用を推奨しない

代わりに、ローカルをパーシャルに渡します:

<%= 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) %>

常に?

このような分離されたパーシャルがおそらく必要ない状況はたくさんありますが、短期的にはインスタンス変数を使用する方が簡単です。ただし、アプリケーションの将来のニーズを予測することは困難です。

そのため、これは比較的低コストでありながら一般的な実践に役立ちます。

42
Edward Anderson

あなたはそれを両方の方法で持つことができます。パーシャルの上部:

<% item ||= @item %>

そうすることで、ローカル変数を渡すかどうかに関係なく機能し、適切なデフォルトを提供しますが、パーシャルの代替使用を禁止しません。

5
Vezquex

私はa)に非常に具体的な理由で投票します-DRY!変数を渡し始める場合-そのように-次に知っていること-それは混乱です-変数の名前の付け方や何かについて何かを変更する必要があるとしましょう-次に、すべてのビューに移動してそれらを変更する必要があります部分的なものの代わりに。また、パーシャルを変更すると、結果がいくつかあるテーブルが生成されるとしましょう。すべてのビューで変更されるため、使用されているビューを確認する必要があります。適切なIDEそれを助けることができるはずですが、ビューの上部に小さなコメントセクションがあることも好きです-ここで、それが使用される場所と理由を説明します-他のプログラマーを助け、あなたが来る必要がある場合に覚えておくのに役立ちますパーシャルに戻って変更します。ただし、パーシャルの重要なポイントは、ビューから何も渡さずに呼び出すことです。そのため、変数が何らかの形で変更された場合に、パーシャルが呼び出されるすべての場所を変更する必要はありません。

結局のところ、これは設計上の選択です。Facebookを実行している場合を除いて、正直に言うと、追加のルックアップはそれほど大きな問題ではありませんが、あまりドライではありません。

PS:ちょうどそれについて考えました-ヘルパーメソッドでパーシャルを呼び出す方法を実際に抽象化できるので、パーシャルを呼び出す方法を変更する必要がある場合は、1つの場所を変更するだけで済みます。

3
konung