Подтвердить что ты не робот

Как рельсы реализуют before_filter?

Мне интересно, как рельсы реализуют фильтры типа before_filter.

Но после чтения исходного кода я все еще запутался.

Я заметил, что структура rails поддерживает filter_chain и запускает фильтры до целевого метода.

Но я не понимаю важный процесс: как рельсы захватывают вызов метода?

Я имею в виду, например, что у меня есть класс Dog, и установите a before_filter в коду метода.

Когда я вызываю dog.bark, рельсы должны каким-то образом захватить это вызов и вместо этого выполнить свой измененный метод.

Однако я не нашел такой код в исходном коде.

Может ли кто-нибудь сказать мне идею или указать, где находится код?

4b9b3361

Ответ 1

Когда вы устанавливаете before_filter или любой подобный фильтр (подумайте after_filter, around_filter), вы делаете это с помощью Symbol или Proc, лямбда или блок.

before_filter :bark
before_filter Proc.new { |k| k.bark }

Приведенный выше добавляет символы или блоки в стек здесь, вызывая set_callback. Это создает цепочку, на которую вы ссылаетесь.

Каждый элемент в этой цепочке является экземпляром класса ActiveSupport::Callbacks::Callback. Этот класс знает

  • Метод (Символ) или его блокировка должен выполняться (т.е. метод вашего класса :bark)
  • Контекст, который должен выполняться внутри (т.е. ваш класс Dog)

Примеры Callback добавляются к ActiveSupport::Callbacks::CallbackChain в __update_callbacks.

Когда каждый Callback класс инициализируется, _compile_filter запускается, чтобы нормализовать фильтр из Symbol, Proc, lambda или block в общий, вызываемый формат.

Наконец, когда выполняется CallbackChain, он вызывает start для каждого экземпляра Callback, а на данный момент, что фильтр действительно выполняется в соответствующем контексте.


Важно отметить, что не создать фильтр, например

before_filter dog.bark

он выполнит dog.bark и передаст ему возвращаемое значение в before_filter, которое будет добавлено к CallbackChain. Цель состоит в том, чтобы передать некоторую инструкцию на before_filter для Rails для последующего выполнения для вас. Вместо этого вы сделаете что-то вроде

before_filter Proc.new { d = Dog.new; d.bark }

Код в Proc не выполняется. когда строка выше выполняется Rails. Вместо этого Rails сообщает передать Proc в CallbackChain. Proc - это "инструкция", которую вы передаете Rails для выполнения в соответствующее время.


как, в первую очередь, знают рельсы, которые я назвал: кора

Для этого предположим, что ваш класс Dog просто определяется как

class Dog
  def bark

  end

  def eat

  end
end

(Хотя это ужасный пример), вы можете захотеть что-то вроде

before_bark :eat

Для этого требуется определить обратный вызов bark, а затем сообщить вашему методу bark для запуска связанных обратных вызовов bark.

class Dog
  extend ActiveModel::Callbacks

  define_callbacks :bark

  before_bark :eat

  def bark
    run_callbacks(:bark) { YOUR BARK CODE HERE }
  end

  def eat

  end
end

Вы можете видеть, как ActiveRecord::Callbacks делает это.

Это действительно плохой пример, потому что вы можете (и должны) просто вызвать eat непосредственно из bark, но это должно получить точку.

Ответ 2

Rails не захватывает вызовы методов так, как вы описываете. Если вы посмотрите на AbstractController::Base.process, он будет искать метод, который нужно вызвать для отправленного действия, запустить фильтры, а затем вызвать фактический метод. Другими словами, ваш метод контроллера не вызывается напрямую, а через этот метод process.