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

Фильтровать для выполнения перед рендером, но после контроллера?

Предположим, что у меня есть какая-то логика в базовом контроллере, чтобы передать информацию в представление, чтобы построить что-то вроде breadcrumb:

class ContextAwareController < ApplicationController

  after_filter :build_breadcrumb

  def build_breadcumb
    #...
  end
end

Я хочу, чтобы этот метод build_breadcrumb запускал после логику основного контроллера, но до визуализировался вид.

Вышеприведенный код запускается слишком поздно, но before_filter будет слишком рано.

Может ли кто-нибудь предложить способ выполнить это без явного вызова build_breadcumb в конце каждого из действий дочерних контроллеров?

Спасибо

4b9b3361

Ответ 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