質問

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

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

私が遭遇した問題は、オブジェクトがロードされた後にいくつかの変数を初期化したいということです(スペルが正しくない人のために初期化してください:P)。そのため、私は after_initialize 針。問題ない...さらにミックスインを追加し始めるまで。

私が抱えている問題は、 after_initialize 私のミックスインのいずれかにあるので、 素晴らしい 最初に呼び出して他のミックスインを確認します after_initialize 電話がかかってきます。これは素晴らしいことですが、最終的に super を呼び出すと、呼び出すスーパーがないためにエラーが発生します。

十分に混乱していない場合に備えて、次の小さな例を示します。

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 呼び出しがある場合、 素晴らしい 電話、どうすれば最後に止められますか 素晴らしい エラーが発生してから呼び出しますか?スーパー メソッドを呼び出す前に、そのメソッドが存在するかどうかをテストするにはどうすればよいですか?

役に立ちましたか?

解決

これを使用できます:

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

他のヒント

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

包含クラス (継承元のクラス) ActiveRecord::Base, 、この場合、これは Iso) できた 独自に定義する after_initialize, 、したがって、以外の解決策はありません alias_method_chain (または元のエイリアスを保存する他のエイリアス)コードを上書きする危険があります。@Orion Edwardsのソリューションは私が思いつく限り最高のものです。他にもありますが、それらは 遠い もっとハックっぽい。

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

後で:

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

そこに簡単な条件を投げ込むだけです。

super if respond_to?('super')

無駄なメソッドを追加しなくても大丈夫です。素敵で清潔です。

スーパー メソッドが存在するかどうかを確認するのではなく、単に定義することもできます

class ActiveRecord::Base
    def after_initialize
    end
end

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top