Как rails (ActiveRecord) определяет метод класса на моделях и как удалить один из них при необходимости - PullRequest
2 голосов
/ 22 июня 2019

Я пытаюсь выяснить это во время моего путешествия к рельсам и глубокому пониманию ruby.

Что я знаю, так это то, что мы можем проверить, определен ли метод в классе ruby ​​ с помощьювызов: method_defined? на объекте.Поскольку все классы также являются объектами класса Class , мы можем сделать то же самое для методов класса .Например, если класс Foo определяет bar метод класса, это происходит следующим образом:

Foo.method_defined? :bar #-> true

Но при применении того же к моделям, которые унаследованы от ActiveRecord::Base (прямо или косвенно).это приводит к:

User.method_defined? :all #-> false
User.method_defined? :count #-> false

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

Пока я могу получить то же объяснениенапример, методы, которые rails добавляет для объектов модели, например, метод name в User.first.name (при условии, что в пользовательской таблице есть столбец имени).Было бы плюсом.

Наконец, несколько слов о том, как удалить один из этих методов, если нам когда-либо понадобится.

ДОПОЛНИТЕЛЬНО: Если я тоже смогу узнатькак сбросить класс User, чтобы метод снова определялся после удаления, например, если я удаляю метод count с предложением из комментариев: User.instance_eval { undef :count } я также хочу иметь возможность переопределить это обратно.Или как бы сбросить класс User.load 'app/models/user.rb' здесь не выполняет эту работу.

Обновление: Я выяснил, как сбросить класс после отмены определения метода в собственном классе модели User перед выполнением load 'app/models/user.rb' iпришлось явно сделать Object.send(:remove_const, :User), так что ruby ​​полностью удаляет класс, чем выполняет загрузку.
Все еще пытается разобраться во всем этом и особенно в том, как работает реализация rails.

Ответы [ 3 ]

1 голос
/ 23 июня 2019

Никакой магии здесь

module X
  def test
  end
end

class A
  extend X
end

class B
  include X
end
A.method_defined? :test #false  
B.method_defined? :test #true 

поэтому он не определен, потому что это метод класса, а методы класса определены в одноэлементном классе. method_defined? проверить, определен ли метод в классе или только в его предках.

B.ancestors #[B, X, Object, Kernel, BasicObject]
A.ancestors #[A, Object, Kernel, BasicObject]

так просто, потому что это метод класса
ОБНОВЛЕНИЕ: добавление дополнительной трассировки в Как все определено

, так что он похож на простой код выше, но использует некоторые из ActiveSupport магии, такие как автозагрузка, egarloading и проблемы.

0 голосов
/ 24 июня 2019

Мы можем удалить метод, используя

User.instance_eval { undef :count }

и может переопределить его в родительском классе, используя

User.instance_eval do
  def count
    super
  end
end

Надеюсь, это поможет вам

0 голосов
/ 22 июня 2019

Не уверен, но.Метод method_defined? заботится об открытых методах экземпляра.Вместо этого, если вы хотите проверить, реагирует ли какой-либо объект на метод (как класс, он также является объектом), используйте respond_to?.

...