Методы алиасинга не одобряются? - PullRequest
0 голосов
/ 16 июня 2009

Я занимаюсь разработкой интернет-магазина, и клиенту нужна возможность удалить заказ и автоматически пополнить его товары (например, для тестовых заказов). Вот моя первая попытка реализовать это:

class Order < ActiveRecord::Base
  def destroy_and_restock
    restock_products
    destroy
  end

  protected

  def restock_products
    line_items.each do |li|    
      li.product.quantity_on_hand += li.quantity
      li.product.save
    end
  end
end

Но что, если мне понадобится создать еще один destroy_and_x метод позже? Почему бы не разрешить передачу этого X в качестве параметра методу destroy()? Так что теперь я собираюсь пойти с этим:

alias :old_destroy :destroy
def destroy(options = {})
  if options['restock'] == true
    restock_products
  end
  old_destroy
end

protected

def restock_products
  line_items.each do |li|    
    li.product.quantity_on_hand += li.quantity
    li.product.save
  end

Это более расширяемое, но заставляет меня чувствовать себя немного грязно. Я не прав, чтобы чувствовать себя грязным? Есть ли лучший способ сделать это?

Ответы [ 4 ]

2 голосов
/ 16 июня 2009

Я бы сказал: «Да, это грязно». Ваше намерение состоит не в том, чтобы изменить поведение метода 'destroy', а в том, чтобы выполнить некоторую работу с доменом, а затем запустить destroy. Ваш первый подход великолепен - определите метод, который делает то, что вы хотите, и при необходимости вызывайте destroy. Я думаю, что «обертывание» или «исправление обезьяны» метод, как вы думаете, это метод, который лучше всего применять, когда нельзя использовать стандартные подходы ОО - например, когда вам нужно изменить / дополнить поведение в класс, который определен и используется вне вашей области контроля.

Даже если вы рассматриваете вопрос об изменении поведения самого метода destroy, я бы предложил переопределить метод здесь, а не оборачивать его:

def destroy(options = {})
  restock_products if options['restock']
  super() # I think parens are necessary here, to avoid passing options up the chain
end
0 голосов
/ 16 июня 2009

Если исправление обезьяны не позволяет вам спать по ночам, вы можете добиться того же самого путем создания подклассов. Когда я нуждаюсь в быстром взломе или быстром отладочном взломе, я также исправляю патч.

0 голосов
/ 16 июня 2009

Гораций, я неправильно понял ваш вопрос. Я думаю, что вы ищете это:

http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

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

Удачи.

0 голосов
/ 16 июня 2009

Как насчет использования блока? Тогда вам не нужно тянуть свои волосы на части во время разработки этого в классе, и вы можете делать больше, когда и вам нужно:

def destroy_after &block
  yield if block
  destroy
end

Тогда назовите это так:

order.destroy_after { order.restock_products }

Я не могу придумать хорошее название для этой функции ... но я надеюсь, что вы поняли.

...