Module: ResponseFor::ActionController::ClassMethods

Included in:
ResponsesModule
Defined in:
lib/response_for/action_controller.rb

Instance Method Summary collapse

Instance Method Details

#action_responsesObject

return action_responses Hash. On initialize, set and return hash whose values are copies of superclass action_responses, if any



101
102
103
# File 'lib/response_for/action_controller.rb', line 101

def action_responses
  instance_variable_get('@action_responses') || instance_variable_set('@action_responses', copy_of_each_of_superclass_action_responses)
end

#include_responses_from(responses_container) ⇒ Object

takes any responses from the argument (a controller, or responses module) and adds them to this controller’s responses



106
107
108
109
110
111
# File 'lib/response_for/action_controller.rb', line 106

def include_responses_from(responses_container)
  responses_container.action_responses.each do |action, responses|
    action_responses[action] ||= []
    action_responses[action].unshift(*responses)
  end
end

#remove_response_for(*actions) ⇒ Object

remove any response for the specified actions. If no arguments are given, then all repsonses for all actions are removed



92
93
94
95
96
97
98
# File 'lib/response_for/action_controller.rb', line 92

def remove_response_for(*actions)
  if actions.empty?
    instance_variable_set('@action_responses', nil)
  else
    actions.each {|action| action_responses.delete(action.to_s)}
  end
end

#response_for(*actions, &block) ⇒ Object

response_for allows you to specify a default response for your actions that don’t specify a respond_to block.

Using response_for, you may keep the response logic out of the action, so that it can be overriden easily without having to rewrite the entire action. This is very useful when subclassing controllers.

Usage

response_for :action1 [, :action2], [,:types => [:mime, :type, :list]] [ do |format| ... end] # or

Example

class FooController < ApplicationController
  def index
    @foos = Foo.find(:all)
  end

  def show
    @foo = Foo.find(params[:id])
  end
end

# this controller needs to respond_to fbml on index, and
# js, html and xml (templates) on index and show
class SpecialFooController < FooController
  response_for :index do |format|
    format.fbml { render :inline => turn_into_facebook(@foos) }
  end

  response_for :index, :show, :types => [:html, :xml, :js]
end

when response_for kicks in

response_for only kicks in if the action (or any filters) have not already redirected or rendered.

This means that if you foresee wanting to override your action’s responses, you should write them without a respond_to block, but with a response_for block (the latter can be overridden by subsequent response_fors, the former cannot)

Other examples

response_for :index, :types => [:fbml]    # index will respond to fbml and try to render, say, index.fbml.builder

response_for :update do |format|          # this example is for a resources_controller controller
  if !(resource.new_record? || resource.changed?) # => resource.saved?
    format.js { render(:update) {|page| page.replace dom_id(resource), :partial => resource }}
  else
    format.js { render(:update) {|page| page.visual_effect :shake, dom_id(resource) }}
  end
end

Notes

  • If the before_filters or action renders or redirects, then response_for will not be invoked.

  • you can stack up multiple response_for calls, the most recent has precedence

  • the specifed block is executed within the controller instance, so you can use controller instance methods and instance variables (i.e. you can make it look just like a regular respond_to block).

  • you can add a response_for an action that has no action method defined. This is just like defining a template for an action that has no action method defined.

  • you can combine the :types option with a block, the block has precedence if you specify the same mime type in both.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/response_for/action_controller.rb', line 75

def response_for(*actions, &block)
  (options = actions.extract_options!).assert_valid_keys(:types)
  
  types_block = if options[:types]
    proc {|responder| Array(options[:types]).each {|type| responder.send type}}
  end
  
  # store responses against action names
  actions.collect(&:to_s).each do |action|
    action_responses[action] ||= []
    action_responses[action].unshift types_block if types_block
    action_responses[action].unshift block if block
  end
end