Фильтровать для выполнения перед рендером, но после контроллера?
Предположим, что у меня есть какая-то логика в базовом контроллере, чтобы передать информацию в представление, чтобы построить что-то вроде breadcrumb:
class ContextAwareController < ApplicationController
after_filter :build_breadcrumb
def build_breadcumb
#...
end
end
Я хочу, чтобы этот метод build_breadcrumb запускал после логику основного контроллера, но до визуализировался вид.
Вышеприведенный код запускается слишком поздно, но before_filter будет слишком рано.
Может ли кто-нибудь предложить способ выполнить это без явного вызова build_breadcumb в конце каждого из действий дочерних контроллеров?
Спасибо
Ответы
Ответ 1
Я считаю, что рендеринг начинается, когда вызывается рендер, и нет способа по умолчанию отложить его. Здесь вы можете сделать одну вещь:
Фильтры применяются в том же объявленном порядке. Поэтому сделайте второй фильтр после вызова, который вызывает рендер с массивами args, хранящимися в переменной класса. Затем в любом месте, где обычно вызывается рендер, задайте переменную.
Ответ 2
У меня была такая же проблема, и я решил это:
class ApplicationController < ActionController::Base
def render *args
add_breadcrumbs
super
end
end
Ответ 3
Есть также некоторые драгоценные камни для достижения этого. Один из них rails3_before_render.
Он работает аналогично фильтрам, например:
class PostsController < ApplicationController
before_render :ping, :except => [:destroy]
def index; end
def new; end
def show; end
def destroy; end
private
def ping
Rails.logger.info "Ping-Pong actions"
end
end
(код скопирован из документации gem)
Ответ 4
Если мы переопределяем render
, мы действительно не используем цепочку фильтров, поэтому было бы проще определить, какое действие мы используем @_action_name
.
StuffController < ApplicationController
def my_filter
# Do the stuff
end
def render(*args)
my_filter if @_action_name == "show"
super
end
end
Ответ 5
Вы можете сделать это, чтобы подделать before_render:
class StuffController < ApplicationController
before_filter :my_filter, only: [:index, :show]
def my_filter
@my_filter = true
end
def _my_filter
# Do the actual stuff here
end
def render(*args)
_my_filter if @my_filter
super
end
end
Спасибо @joshua-muheim за подсказку об использовании render