سؤال

حسنًا، لقد قمت بإعادة بناء الكود الخاص بي في تطبيق Rails الصغير الخاص بي في محاولة لإزالة التكرار، وبشكل عام لجعل حياتي أسهل (لأنني أحب الحياة السهلة).كان جزء من عملية إعادة البناء هذه هو نقل التعليمات البرمجية المشتركة بين نموذجين من نماذجي إلى وحدة نمطية يمكنني تضمينها في المكان الذي أحتاج إليه.

حتى الان جيدة جدا.يبدو أن الأمر سينجح، لكنني واجهت للتو مشكلة لست متأكدًا من كيفية حلها.الوحدة (التي أسميتها قابلة للإرسال)، ستكون مجرد رمز يتعامل مع إرسال الفاكس أو البريد الإلكتروني أو طباعة ملف PDF للمستند.لذلك، على سبيل المثال، لدي أمر شراء، ولدي أوامر مبيعات داخلية (يتم اختصارها بشكل خيالي إلى ISO).

المشكلة التي واجهتها هي أنني أريد تهيئة بعض المتغيرات (تهيئتها للأشخاص الذين لا يتهجؤون بشكل صحيح :P ) بعد تحميل الكائن، لذلك كنت أستخدم after_initialize خطاف.لا مشكلة...حتى أبدأ بإضافة المزيد من الخلطات.

المشكلة التي أواجهها هي أنه يمكنني الحصول على after_initialize في أي من الخلطات الخاصة بي، لذا أحتاج إلى تضمين ملف ممتاز اتصل في البداية للتأكد من الخلط الآخر after_initialize يتم استدعاء المكالمات.وهو أمر رائع، حتى ينتهي بي الأمر بالاتصال بـ Super وأحصل على خطأ لأنه لا يوجد 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، مع a ممتاز اتصل، كيف يمكنني إيقاف هذا الأخير ممتاز استدعاء من رفع الخطأ؟كيف يمكنني اختبار وجود الطريقة الفائقة قبل أن أسميها؟

هل كانت مفيدة؟

المحلول

يمكنك استخدام هذا:

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