Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter to execute before render but after controller?

Suppose I have some logic in a base controller to pass information to the view to build something like a breadcrumb:

class ContextAwareController < ApplicationController

  after_filter :build_breadcrumb

  def build_breadcumb
    #...
  end
end

I want this build_breadcrumb method to run after the main controller logic, but before the view is rendered.

The above code runs too late, but a before_filter would be too early.

Can anybody suggest a way to accomplish this without explicitly calling build_breadcumb at the end of each of the actions in the child controllers?

Thanks

like image 205
Chris Avatar asked Feb 14 '12 17:02

Chris


4 Answers

I had the same problem and solved it like this:

class ApplicationController < ActionController::Base
  def render *args
    add_breadcrumbs
    super
  end
end
like image 82
Joshua Muheim Avatar answered Nov 19 '22 00:11

Joshua Muheim


There are also some gems to achieve this. One of them is rails3_before_render. It works similarly to filters, for example:

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

(code snipped copied from gem documentation)

like image 28
knarewski Avatar answered Nov 18 '22 23:11

knarewski


I believe rendering starts when render is called, and there's no default way to defer it. Here's one thing you could do:

filters are applied in the same order declared. So make a second after-filter that calls render with an array args stored in a class variable. Then anywhere you would normally call render, set the variable.

like image 2
Peter Ehrlich Avatar answered Nov 19 '22 00:11

Peter Ehrlich


If we're overriding render, we're not really using the filter chain at all, so it might be simpler to determine which action we're in using the @_action_name.

StuffController < ApplicationController

  def my_filter
    # Do the stuff
  end

  def render(*args)
    my_filter if @_action_name == "show"
    super
  end

end
like image 2
Isaac Freeman Avatar answered Nov 19 '22 00:11

Isaac Freeman