35

さて、私は小さなRailsアプリでコードをリファクタリングして、重複を取り除き、一般的に私の生活を楽にしてきました(私は簡単な生活が好きなので)。このリファクタリングの一環として、2つのモデルに共通するコードを、必要な場所に含めることができるモジュールに移動しました。

ここまでは順調ですね。うまくいくように見えますが、どうすればよいかわからないという問題が発生しました。モジュール(私はsendableと呼んでいます)は、ファックス、電子メール、またはドキュメントのPDFの印刷を処理するコードになります。たとえば、私には発注書があり、内部販売注文(想像上はISOと略されます)があります。

私が直面した問題は、オブジェクトがロードされた後にいくつかの変数を初期化(スペルが正しくない人のために初期化:P)したいので、after_initializeフックを使用していることです。問題ありません...ミックスインを追加し始めるまで。

私が抱えている問題は、どのミックスインにも含めることができるということです。そのため、他のミックスインコールが確実に呼び出されるように、最初にスーパーafter_initializeコールを含める必要があります。スーパーを呼び出すことになり、呼び出すスーパーがないためにエラーが発生するまでは、これはすばらしいことです。after_initialize

私が十分に混乱していない場合に備えて、ここに小さな例があります:

class Iso < ActiveRecord::Base
  include Shared::TracksSerialNumberExtension
  include Shared::OrderLines
  extend  Shared::Filtered
  include Sendable::Model

  validates_presence_of   :customer
  validates_associated    :lines

  owned_by                :customer
  order_lines             :despatched # Mixin

  tracks_serial_numbers   :items  # Mixin

  sendable :customer                      # Mixin

  attr_accessor :address

  def initialize( params = nil )
    super
    self.created_at ||= Time.now.to_date
  end
end

したがって、各ミックスインにスーパー呼び出しを伴うafter_initialize呼び出しがある場合、最後のスーパー呼び出しでエラーが発生するのを防ぐにはどうすればよいですか?スーパーメソッドを呼び出す前に、スーパーメソッドが存在することをテストするにはどうすればよいですか?

4

5 に答える 5

42

これを使用できます:

super if defined?(super)

次に例を示します。

class A
end

class B < A
  def t
    super if defined?(super)
    puts "Hi from B"
  end
end

B.new.t
于 2010-10-05T20:34:17.547 に答える
3

試しましたalias_method_chainか?基本的に、すべての通話を連鎖させることができますafter_initialize。これはデコレータのように機能します。新しいメソッドごとに新しい機能レイヤーが追加され、残りを実行するためにコントロールが「オーバーライドされた」メソッドに渡されます。

于 2008-08-14T22:37:56.463 に答える
3

包含クラス ( から継承するものActiveRecord::Base、この場合はIso)は独自の を定義できるため、 (またはオリジナルを保存する他のエイリアシング)after_initialize以外のソリューションはコードを上書きするリスクがあります。alias_method_chain@Orion Edwardsのソリューションは、私が思いつくことができる最高のものです。他にもありますが、それらははるかにハックです。

alias_method_chainまた、 after_initialize メソッドの名前付きバージョンを作成できるという利点もあります。つまり、重要なまれなケースで呼び出し順序をカスタマイズできます。それ以外の場合は、インクルード クラスにミックスインが含まれる順序に翻弄されます。

後で

すべてのコールバックのデフォルトの空の実装の作成について、ruby-on-rails-core メーリング リストに質問を投稿しました。とにかく、保存プロセスはそれらすべてをチェックするので、なぜそれらがそこにあってはならないのかわかりません。唯一の欠点は余分な空のスタック フレームを作成することですが、既知のすべての実装ではかなり安価です。

于 2008-08-15T01:28:04.920 に答える
2

そこに簡単な条件を投げることができます:

super if respond_to?('super')

そして、あなたは大丈夫です-役に立たないメソッドを追加する必要はありません。素敵できれい。

于 2009-05-25T06:53:52.397 に答える
0

スーパーメソッドが存在するかどうかを確認するのではなく、定義するだけです

class ActiveRecord::Base
    def after_initialize
    end
end

これは私のテストで機能し、既存のコードを壊すことはありません。これを定義する他のすべてのクラスは、とにかくこのメソッドを黙ってオーバーライドするだけだからです。

于 2008-08-14T21:30:58.813 に答える