ruby alias_method в методе класса

Кажется, что alias_method не работает в блоке класса << сам по себе так же, как снаружи. В частности, когда я использую alias_method для метода экземпляра и впоследствии перезаписываю метод, псевдоним можно использовать для доступа к исходному методу. Однако я не могу сделать это с помощью метода класса.

Это мой вариант использования: я переопределяю методы destroy и destroy_all, которые унаследованы от базы ActiveRecord, потому что код, как написано в настоящее время, позволяет очень легко случайно удалить строки, когда вы намеревались удалить записи соединения. Этот дизайн может измениться в более крупном проекте, но сейчас это мое решение, поскольку по большей части никто не захочет удалять строки из этой таблицы. Но для того, чтобы разрешить намеренное удаление строк в таблице для благих намерений, я использую alias_method, чтобы сохранить дескриптор оригинальных методов destroy и destroy_all. Использование псевдонима работает для доступа к оригинальному методу: destroy (instance), но не позволяет мне получить доступ к оригинальному методу: desotry_all (class)

class HoldReason < ActiveRecord::Base
  class << self
    alias_method :remove_hold_reasons_from_table, :destroy_all

    def destroy_all
      raise "Nope"
    end
  end

  alias_method :remove_hold_reason, :destroy

  def destroy
    raise "Nope"
  end
end

Здесь мы видим, что хотя эта стратегия работает для метода экземпляра, чтобы разрешить успешное удаление одной строки:

> HoldReason.find_by(title: "Management Review").remove_hold_reason
  HoldReason Load (0.7ms)  SELECT  `hold_reasons`.* FROM `hold_reasons` WHERE `hold_reasons`.`title` = 'Management Review' LIMIT 1
   (0.5ms)  BEGIN
  SQL (4.6ms)  DELETE FROM `hold_reasons` WHERE `hold_reasons`.`id` = 23
   (0.6ms)  COMMIT
=> #<HoldReason id: 23, title: "Management Review", category: "Operations">

Я не могу получить доступ к оригинальному методу: destroy_all для удаления нескольких строк в одном запросе; вместо этого я получаю переопределенный метод, даже когда я использую псевдоним:

> HoldReason.remove_hold_reasons_from_table
  HoldReason Load (0.7ms)  SELECT `hold_reasons`.* FROM `hold_reasons`
RuntimeError: Nope

Что происходит, что я не могу сделать это для методов класса, и как я могу это исправить (кроме просто использовать необработанный запрос SQL для удаления)?

1 ответ

Ответ в том, что я не получал новый метод: destroy_all; Я правильно получал старый метод: destroy_all, и он назывался: уничтожить под капотом. Конечно, вызвав: destroy, он получил новый метод: destroy, который вызвал ошибку. Таким образом, казалось, что я получаю новый метод класса, потому что новый метод класса и новый метод экземпляра вызывают точно такую ​​же ошибку.

Это станет понятнее, если я немного изменю это:

class HoldReason < ActiveRecord::Base
  class << self
    alias_method :remove_hold_reasons_from_table, :destroy_all

    def destroy_all
      raise "Don't destroy_all (multiple: class method)"
    end
  end

  alias_method :remove_hold_reason, :destroy

  def destroy
    raise "Don't destroy (single: instance method)"
  end

end

результаты в

> HoldReason.remove_hold_reasons_from_table
RuntimeError: Don't destroy (single: instance method)
Другие вопросы по тегам