web-dev-qa-db-ja.com

定義された? Ruby and Rails

私はERBの上に書かれたかなり古いテンプレートシステムを持っています。データベースに格納されているERBテンプレートに依存しています。それらは読み取られ、レンダリングされます。あるテンプレートから別のテンプレートにデータを渡したいときは、:localsパラメータをRails renderメソッドに使用します。一部のテンプレートでこれらの変数のデフォルト変数を設定するために、私は単に以下を通知するdefined?メソッドを使用します。ローカル変数が定義されている場合は私、そうでない場合は次のようなデフォルト値で初期化します。

unless defined?(perex)
  perex = true
end

私はアプリを最新のRailsにアップグレードしていて、奇妙な動作が見られます。基本的に、これは時々機能し(時々perexが未定義)、機能しない場合があります(perexが定義されてnilに設定されています)。何も変更せずに発生します。

2つの質問があります:定義を使用する以外に良い方法はありますか?信頼性が低いことが証明されています(数年前から信頼性が高かったRails 1.6)?このような方法では、すべてのテンプレートが書き換えられることはないはずです。Ruby docsおよびdefined?メソッドについて何も見つけることができませんでした。非推奨ですか、それとも単純なブラインドですか?

編集:実際の問題は、Ruby/eRBのバグのようです。 nlessステートメントが機能する場合もありますが、機能しない場合もあります。奇妙なことに、2行目が実行されたとしても、perex stilは残りの部分でnilのままです。定義済みを削除しますか?それを解決しました。

27
Honza

まず、実際には、 defined?は演算子です

第二に、私があなたの質問を正しく理解しているなら、それを行う方法はこれRubyイディオム:

perex ||= true

未定義またはperexの場合、nilにtrueが割り当てられます。値がnilの場合、割り当ては評価されないため、これはあなたの例が正確に行うことではありませんが、それに依存している場合、私の意見では、それを見ることなく、明確に書いていませんコード。

Edit:Honzaが述べたように、上記のステートメントはperexの値がfalseの場合に置き換えます。次に、最小行数を書き換えるために次のことを提案します。

perex ||= perex.nil?  # Assign true only when perex is undefined or nil
38
Rômulo Ceccon

ローカルがRailsテンプレートで定義されているかどうかをテストする最も安全な方法は次のとおりです:

local_assigns[:perex]

これは、Rails APIとdefined?は実装上の制限により使用できません。

24
mislav

ミスラフの答えに従って、私はRails APIでそのドキュメントを探し、そしてそれを Class ActionView :: Base (見出し "ローカル変数をサブに渡すテンプレート」)。ただし、mislavが行うこと以上のことはほとんど言っていないため、検索する価値はほとんどありませんでした。

if local_assigns.has_key? :perex
12
KenB

mislavの元の回答KenBの詳細 を考慮すると、次の方法が絶対的に最善のアプローチだと思います(私は意見を述べますが)。キーが元のハッシュに存在しない場合、Rubyの Hash#fetch メソッドを使用して代替値にフォールバックします。

perex = local_assigns.fetch(:perex, true)

これは、false値を許可したい場合があるため、ほとんどのユーザーが提案する||=メソッドよりも優れています。たとえば、次のコードではneverを使用してfalse値を渡すことができます。

perex = local_assigns[:perex] || true
6
Matt Huggins