Какую технику 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's 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
В чистом рубине я бы ожидал позвонить super
чтобы получить такое поведение.
Я предполагаю, что Rails использует какую-то технику метапрограммирования, чтобы гарантировать, что мои методы контроллера будут вызывать super
, Если так, может кто-нибудь объяснить это? Можете ли вы указать на исходный код, который делает это?
Обновить
Как указал Младен Ябланович, моя первоначальная ментальная модель была неправильной; метод контроллера обычно не отображает представление; вместо этого и метод контроллера, и рендеринг представления вызываются неким кодом инфраструктуры. Это очевидно, потому что я могу создать метод контроллера с любым именем - например, search
- и search
представление будет предоставлено. Ясно, что в этом случае я не переопределяю родительский метод, и некоторый каркасный код анализирует имя метода контроллера и ищет подходящее представление.
Тем не менее, фреймворк должен быть в состоянии определить, вызван или нет метод контроллера render
, Так что это еще одна маленькая загадка для меня.
3 ответа
На контроллере есть метод render_for_text
, Это берет строку и устанавливает результат как тело ответа. Даже если вы не отображаете текст, рендеринг файла представления просто читает содержимое файла, оценивает его и передает его render_for_text
метод. Затем метод сохраняет наборы переменных экземпляра с именем @performed_render
в true
, который сообщает rails, что контроллер уже предоставил представление.
Затем существует метод, называемый performed?
это указывает, было ли вызвано действие рендеринга. Это делается путем проверки, если @performed_render
или же @performed_redirect
правда.
Учитывая вышеприведенную информацию, самая первая строка метода рендера должна иметь смысл, и, надеюсь, ответит на ваш вопрос:
raise DoubleRenderError, "Can only render or redirect once per action" if performed?
Несколько лет назад здесь Джемис Бак много писал о неявных маршрутах.
Я считаю, что код, который вы ищете, находится в Ресурсах. Rails просматривает входящий запрос и (для маршрутов RESTful) идет сюда, чтобы определить контроллер и действие, если они не указаны.
Обновление: Контроллеры - действительно сложная часть инфраструктуры Rails. Это не так просто, как отдельный класс Ruby с одним методом (вот почему super
на самом деле не требуется, но серия вызовов до и после вызова вашего индивидуального метода.
Rack обрабатывает запрос и передает его Rails, который выполняет маршрутизацию, делегирует экземпляру ActionController для действия (которое может быть или не было вами написано), а затем передает результат этого процессу рендеринга.
При визуализации представления Rails инициализирует экземпляр соответствующего шаблона представления копиями переменных экземпляра в контроллере. Таким образом, переменные экземпляра на самом деле не наследуются представлением, а копируются из контроллера в представление перед отображением представления.
Я не искал точных деталей в источнике, но вышеприведенное объяснение должно по крайней мере обрисовать общее представление о том, как это работает.