2016-03-11 4 views
1

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

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

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-запрос для удаления)?

+0

Ваш вопрос остается неясным. Выделенный фрагмент кода ясно показывает, что 'alias_method' * does * работает: в противном случае вы получите' NoMethodError'. –

+0

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

+0

Извините, я до сих пор не понимаю. В обоих случаях вы можете вызвать метод под его псевдонимом. Итак, 'alias_method' работает в обоих случаях. Между этими двумя случаями нет разницы. В классе 'Module' существует ровно * одна реализация' alias_method', и она работает точно так же для * all * modules, будь то * актуальные * модули, классы или одноэлементные классы. 'alias_method' делает одно и только одно: скопируйте метод под новым именем. Период. И это работает, о чем свидетельствует тот факт, что вы не получаете «NoMethodError». –

ответ

0

Ответ заключается в том, что я не получал новый метод: 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)