Вопрос

Итак, я провел рефакторинг своего кода в моем маленьком приложении Rails, пытаясь устранить дублирование и в целом облегчить себе жизнь (поскольку я люблю легкую жизнь).Частью этого рефакторинга было перемещение кода, общего для двух моих моделей, в модуль, который я могу включить туда, где мне это нужно.

Пока все идет так хорошо.Похоже, это сработает, но я только что столкнулся с проблемой, которую не уверен, как обойти.Модуль (который я назвал sendable) - это просто код, который обрабатывает отправку факсов, электронных писем или печать 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, с супер колл, как я могу остановить это последнее супер вызов из-за сообщения об ошибке?Как я могу проверить, существует ли суперметод, прежде чем я его вызову?

Это было полезно?

Решение

Вы можете использовать это:

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 (или другое сглаживание, которое сохраняет оригинал) может привести к перезаписи кода.Решение Ориона Эдвардса - лучшее, что я могу придумать.Есть и другие, но они такие далеко более халтурный.

alias_method_chain также имеет преимущество создания именованных версий метода after_initialize, что означает, что вы можете настроить порядок вызовов в тех редких случаях, когда это имеет значение.В противном случае вы находитесь во власти любого порядка, в котором класс including включает миксины.

позже:

Я отправил вопрос в список рассылки ruby-on-rails-core о создании пустых реализаций по умолчанию для всех обратных вызовов.Процесс сохранения все равно проверяет их все, так что я не понимаю, почему их там не должно быть.Единственным недостатком является создание дополнительных пустых фреймов стека, но это довольно дешево в любой известной реализации.

Вы можете просто ввести туда краткое условие:

super if respond_to?('super')

и с вами все должно быть в порядке - никаких добавлений бесполезных методов;красиво и чисто.

Вместо того чтобы проверять, существует ли суперметод, вы можете просто определить его

class ActiveRecord::Base
    def after_initialize
    end
end

Это работает в моем тестировании и не должно нарушать какой-либо из ваших существующих кодов, потому что все ваши другие классы, которые его определяют, все равно будут просто молча переопределять этот метод

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top