Цепочки ответственности и проблемы alias_method в Ruby

Я пытаюсь реализовать шаблон цепочки ответственности в Ruby и ActiveRecord для полиморфного объекта. У меня есть несколько проблем.

  • Иногда я получаю сообщение об ошибке, что метод не определен, когда я пытаюсь alias_method его, я думаю, что это потому, что класс не загружен или что-то, поэтому я просто делаю посылку, чтобы получить метод
  • Я получаю кучу бесконечных цепочек, где функция с псевдонимом (original_method) вызывает метод, который вызывает original_method. Мне интересно, если это так, потому что когда вы создаете псевдоним метода, который уже был перезаписан, вы по сути делаете "original_method" копией псевдонима метода.
  • В настоящее время я работаю над этим, имея функцию типа "цепочка", возвращающую подкласс Setting со всеми определенными методами, но мне любопытно, почему было так много проблем с alias_method прямо в классе.

Вот пример:

class Hospital
  has_one :setting, :as => :settable
  belongs_to :administrative_area

  def next_link
    adminstrative_area
  end

  def usable_setting
    setting ? setting : next_link.usable_setting
  end
end

Тогда у меня есть объект Setting:

class Setting < ActiveRecord::Base

belongs_to :settable, :polymorphic => true

def chained
  %w(api_key active_days).each do |method|

    # this is here because otherwise the method isn't defined,
    # it's almost as while it's going up, the metaclass doesn't have the columns
    # until it loads, probably will be fixed if we cache classes
    self.send method.to_sym

    (class << self; self; end).class_eval do

      define_method method do |*args|
        alias_method "original_#{method}", method
        my_setting = send("original_#{method}")
        if my_setting.nil? or my_setting.empty?
          settable.next_link.usable_setting.chained.send(method)
        else
          return my_setting
        end
      end
    end
  end
  self
end
end

1 ответ

Вы, кажется, слишком усложняете. Кажется, вы пытаетесь увидеть, существуют ли api_key и active_days, и если нет, то получите его откуда-то еще.

Вот правильный способ сделать это, предполагая, что api_key и active_days являются столбцами в вашей таблице:

class Setting < ActiveRecord::Base

  belongs_to :settable, :polymorphic => true

  def api_key
    super || settable.next_link.usable_setting.api_key
  end

  def active_days
    super || settable.next_link.usable_setting.active_days
  end
end

Вы можете немного изменить его, чтобы сохранить ясность и удалить дубликаты.

class Setting < ActiveRecord::Base

  belongs_to :settable, :polymorphic => true

  def api_key
    super || next_usable_setting.api_key
  end

  def active_days
    super || next_usable_setting.active_days
  end

  private
  def next_usable_setting
    settable.next_link.usable_setting
  end
end

Так что в этом случае обратите внимание - если у вас есть api_key/active_days, он будет возвращен. В противном случае он будет извлекать usable_setting из next_link. Если у этого есть api_key/active_days, он будет возвращен, в противном случае он получит usable_setting из next_link. И т.п.

Другие вопросы по тегам