Какой метод Ruby использует Rails, чтобы мои методы управления отображали представления?

Просто любопытно, знает ли кто-нибудь, что Ruby-техника используется для выполнения следующего в Rails-инфраструктуре.

Если я не пишу, скажем, метод index на контроллере Rails, Rails все равно будет отображать файл индекса, если URL-адрес соответствует этому маршруту. Это имеет смысл, потому что мой контроллер наследует родительский класс, который должен иметь свой собственный метод index.

Однако, если я сделать определить метод index и только указать ему, чтобы установить переменную экземпляра, он по-прежнему отображает соответствующее представление. Например:

def index
  @weasels = Weasel.all

  # If I omit this line, Rails renders the index anyway.
  # If this behavior is defined in the parent class index method,
  # it seems that by overriding the method, my index wouldn't do it. 
  # I'm not explicitly calling super to get the method from 
  # ActionController::Base, but maybe Rails is doing something like that?
  render :index
end

В чистом Ruby я ожидаю, что вы вызовете super, чтобы получить это поведение.

Я предполагаю, что Rails использует какой-то метод метапрограммирования, чтобы гарантировать, что мои методы контроллера вызовут super. Если да, может ли кто-нибудь объяснить это? Можете ли вы указать на исходный код, который делает это?

Update

Как отметил Младен Ябланович, моя первоначальная ментальная модель была неправильной; метод контроллера обычно не отображает представление; вместо этого и метод контроллера и рендеринг вида вызывается некоторым кодом инфраструктуры. Это очевидно, потому что я могу создать метод контроллера с любым именем - например, search - и будет отображаться представление search. Так что я не переопределяю родительский метод в этом случае, а некоторый код рамки анализирует имя метода контроллера и ищет подходящий вид.

Тем не менее, структура должна быть способна определить, уже или нет метод контроллера render. Так что еще одна маленькая загадка для меня.

Ответ 1

На контроллере есть метод render_for_text. Это берет строку и задает результат как тело ответа. Даже если вы не визуализируете текст, рендеринг файла вида просто считывает содержимое файла, оценивает его и передает его методу render_for_text. Затем в этом методе хранится набор экземпляров с именем @performed_render - true, который сообщает рельсам, что контроллер уже отобразил представление.

Тогда существует метод под названием performed?, который указывает, было ли вызвано действие визуализации. Он делает это, проверяя, истинно ли @performed_render или @performed_redirect.

С приведенной выше информацией самая первая строка метода визуализации должна иметь смысл сейчас и, надеюсь, ответит на ваш вопрос:

raise DoubleRenderError, "Can only render or redirect once per action" if performed?

Ответ 2

При визуализации представления Rails инициализирует экземпляр соответствующего шаблона представления с копиями переменных экземпляра в контроллере. Таким образом, переменные экземпляра на самом деле не унаследованы представлением, а скорее скопированы из контроллера в представление перед визуализацией представления.

Я не искал точных деталей в источнике, но приведенное выше объяснение должно хотя бы очертить общую идею того, как это работает.

Ответ 3

Jamis Buck написал немного о неявных маршрутах несколько лет назад здесь.

Я считаю, что код, который вы ищете, находится в Ресурсах. Rails смотрит на входящий запрос и (для маршрутов RESTful) идет здесь, чтобы определить контроллер и действие, если они не указаны.

Обновление: Контроллеры - действительно сложная часть Rails-инфраструктуры. Это не так просто, как один класс Ruby с единственным методом (поэтому super действительно не нужен, но вызывается серия вызовов как до, так и после вашего индивидуального метода.

Rack обрабатывает запрос и передает его Rails, который выполняет маршрутизацию, делегирует экземпляр ActionController для действия (которое может быть или не быть закодировано вами), а затем передает результат этого процесса рендеринга.