Upgraded Rails and RSpec
[monkeycharger.git] / vendor / rails / actionpack / lib / action_controller / base.rb
blob5249fd035a4bcccca6f5c2cce6cbdf290ce0e60f
1 require 'action_controller/mime_type'
2 require 'action_controller/request'
3 require 'action_controller/response'
4 require 'action_controller/routing'
5 require 'action_controller/resources'
6 require 'action_controller/url_rewriter'
7 require 'action_controller/status_codes'
8 require 'drb'
9 require 'set'
11 module ActionController #:nodoc:
12   class ActionControllerError < StandardError #:nodoc:
13   end
15   class SessionRestoreError < ActionControllerError #:nodoc:
16   end
18   class MissingTemplate < ActionControllerError #:nodoc:
19   end
21   class RenderError < ActionControllerError #:nodoc:
22   end
24   class RoutingError < ActionControllerError #:nodoc:
25     attr_reader :failures
26     def initialize(message, failures=[])
27       super(message)
28       @failures = failures
29     end
30   end
32   class MethodNotAllowed < ActionControllerError #:nodoc:
33     attr_reader :allowed_methods
35     def initialize(*allowed_methods)
36       super("Only #{allowed_methods.to_sentence} requests are allowed.")
37       @allowed_methods = allowed_methods
38     end
40     def allowed_methods_header
41       allowed_methods.map { |method_symbol| method_symbol.to_s.upcase } * ', '
42     end
44     def handle_response!(response)
45       response.headers['Allow'] ||= allowed_methods_header
46     end
47   end
49   class NotImplemented < MethodNotAllowed #:nodoc:
50   end
52   class UnknownController < ActionControllerError #:nodoc:
53   end
55   class UnknownAction < ActionControllerError #:nodoc:
56   end
58   class MissingFile < ActionControllerError #:nodoc:
59   end
61   class RenderError < ActionControllerError #:nodoc:
62   end
64   class SessionOverflowError < ActionControllerError #:nodoc:
65     DEFAULT_MESSAGE = 'Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data.'
67     def initialize(message = nil)
68       super(message || DEFAULT_MESSAGE)
69     end
70   end
72   class DoubleRenderError < ActionControllerError #:nodoc:
73     DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\". Finally, note that to cause a before filter to halt execution of the rest of the filter chain, the filter must return false, explicitly, so \"render(...) and return false\"."
75     def initialize(message = nil)
76       super(message || DEFAULT_MESSAGE)
77     end
78   end
80   class RedirectBackError < ActionControllerError #:nodoc:
81     DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].'
83     def initialize(message = nil)
84       super(message || DEFAULT_MESSAGE)
85     end
86   end
89   # Action Controllers are the core of a web request in Rails. They are made up of one or more actions that are executed
90   # on request and then either render a template or redirect to another action. An action is defined as a public method
91   # on the controller, which will automatically be made accessible to the web-server through Rails Routes.
92   #
93   # A sample controller could look like this:
94   #
95   #   class GuestBookController < ActionController::Base
96   #     def index
97   #       @entries = Entry.find(:all)
98   #     end
99   #
100   #     def sign
101   #       Entry.create(params[:entry])
102   #       redirect_to :action => "index"
103   #     end
104   #   end
105   #
106   # Actions, by default, render a template in the <tt>app/views</tt> directory corresponding to the name of the controller and action
107   # after executing code in the action. For example, the +index+ action of the +GuestBookController+  would render the
108   # template <tt>app/views/guestbook/index.erb</tt> by default after populating the <tt>@entries</tt> instance variable.
109   #
110   # Unlike index, the sign action will not render a template. After performing its main purpose (creating a
111   # new entry in the guest book), it initiates a redirect instead. This redirect works by returning an external
112   # "302 Moved" HTTP response that takes the user to the index action.
113   #
114   # The index and sign represent the two basic action archetypes used in Action Controllers. Get-and-show and do-and-redirect.
115   # Most actions are variations of these themes.
116   #
117   # == Requests
118   #
119   # Requests are processed by the Action Controller framework by extracting the value of the "action" key in the request parameters.
120   # This value should hold the name of the action to be performed. Once the action has been identified, the remaining
121   # request parameters, the session (if one is available), and the full request with all the http headers are made available to
122   # the action through instance variables. Then the action is performed.
123   #
124   # The full request object is available with the request accessor and is primarily used to query for http headers. These queries
125   # are made by accessing the environment hash, like this:
126   #
127   #   def server_ip
128   #     location = request.env["SERVER_ADDR"]
129   #     render :text => "This server hosted at #{location}"
130   #   end
131   #
132   # == Parameters
133   #
134   # All request parameters, whether they come from a GET or POST request, or from the URL, are available through the params method
135   # which returns a hash. For example, an action that was performed through <tt>/weblog/list?category=All&limit=5</tt> will include
136   # <tt>{ "category" => "All", "limit" => 5 }</tt> in params.
137   #
138   # It's also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as:
139   #
140   #   <input type="text" name="post[name]" value="david">
141   #   <input type="text" name="post[address]" value="hyacintvej">
142   #
143   # A request stemming from a form holding these inputs will include <tt>{ "post" => { "name" => "david", "address" => "hyacintvej" } }</tt>.
144   # If the address input had been named "post[address][street]", the params would have included
145   # <tt>{ "post" => { "address" => { "street" => "hyacintvej" } } }</tt>. There's no limit to the depth of the nesting.
146   #
147   # == Sessions
148   #
149   # Sessions allows you to store objects in between requests. This is useful for objects that are not yet ready to be persisted,
150   # such as a Signup object constructed in a multi-paged process, or objects that don't change much and are needed all the time, such
151   # as a User object for a system that requires login. The session should not be used, however, as a cache for objects where it's likely
152   # they could be changed unknowingly. It's usually too much work to keep it all synchronized -- something databases already excel at.
153   #
154   # You can place objects in the session by using the <tt>session</tt> method, which accesses a hash:
155   #
156   #   session[:person] = Person.authenticate(user_name, password)
157   #
158   # And retrieved again through the same hash:
159   #
160   #   Hello #{session[:person]}
161   #
162   # For removing objects from the session, you can either assign a single key to nil, like <tt>session[:person] = nil</tt>, or you can
163   # remove the entire session with reset_session.
164   #
165   # Sessions are stored in a browser cookie that's crytographically signed, but unencrypted, by default. This prevents
166   # the user from tampering with the session but also allows him to see its contents.
167   #
168   # Do not put secret information in session!
169   #
170   # Other options for session storage are:
171   #
172   # ActiveRecordStore: sessions are stored in your database, which works better than PStore with multiple app servers and,
173   # unlike CookieStore, hides your session contents from the user. To use ActiveRecordStore, set
174   #
175   #   config.action_controller.session_store = :active_record_store
176   #
177   # in your <tt>environment.rb</tt> and run <tt>rake db:sessions:create</tt>.
178   #
179   # MemCacheStore: sessions are stored as entries in your memcached cache.  Set the session store type in <tt>environment.rb</tt>:
180   #
181   #   config.action_controller.session_store = :mem_cache_store
182   #
183   #  This assumes that memcached has been installed and configured properly.  See the MemCacheStore docs for more information.
184   #
185   # == Responses
186   #
187   # Each action results in a response, which holds the headers and document to be sent to the user's browser. The actual response
188   # object is generated automatically through the use of renders and redirects and requires no user intervention.
189   #
190   # == Renders
191   #
192   # Action Controller sends content to the user by using one of five rendering methods. The most versatile and common is the rendering
193   # of a template. Included in the Action Pack is the Action View, which enables rendering of ERb templates. It's automatically configured.
194   # The controller passes objects to the view by assigning instance variables:
195   #
196   #   def show
197   #     @post = Post.find(params[:id])
198   #   end
199   #
200   # Which are then automatically available to the view:
201   #
202   #   Title: <%= @post.title %>
203   #
204   # You don't have to rely on the automated rendering. Especially actions that could result in the rendering of different templates will use
205   # the manual rendering methods:
206   #
207   #   def search
208   #     @results = Search.find(params[:query])
209   #     case @results
210   #       when 0 then render :action => "no_results"
211   #       when 1 then render :action => "show"
212   #       when 2..10 then render :action => "show_many"
213   #     end
214   #   end
215   #
216   # Read more about writing ERb and Builder templates in link:classes/ActionView/Base.html.
217   #
218   # == Redirects
219   #
220   # Redirects are used to move from one action to another. For example, after a <tt>create</tt> action, which stores a blog entry to a database,
221   # we might like to show the user the new entry. Because we're following good DRY principles (Don't Repeat Yourself), we're going to reuse (and redirect to)
222   # a <tt>show</tt> action that we'll assume has already been created. The code might look like this:
223   #
224   #   def create
225   #     @entry = Entry.new(params[:entry])
226   #     if @entry.save
227   #       # The entry was saved correctly, redirect to show
228   #       redirect_to :action => 'show', :id => @entry.id
229   #     else
230   #       # things didn't go so well, do something else
231   #     end
232   #   end
233   #
234   # In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method which is then executed.
235   #
236   # == Calling multiple redirects or renders
237   #
238   # An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError:
239   #
240   #   def do_something
241   #     redirect_to :action => "elsewhere"
242   #     render :action => "overthere" # raises DoubleRenderError
243   #   end
244   #
245   # If you need to redirect on the condition of something, then be sure to add "and return" to halt execution.
246   #
247   #   def do_something
248   #     redirect_to(:action => "elsewhere") and return if monkeys.nil?
249   #     render :action => "overthere" # won't be called unless monkeys is nil
250   #   end
251   #
252   class Base
253     DEFAULT_RENDER_STATUS_CODE = "200 OK"
255     include StatusCodes
257     # Determines whether the view has access to controller internals @request, @response, @session, and @template.
258     # By default, it does.
259     @@view_controller_internals = true
260     cattr_accessor :view_controller_internals
262     # Protected instance variable cache
263     @@protected_variables_cache = nil
264     cattr_accessor :protected_variables_cache
266     # Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
267     # and images to a dedicated asset server away from the main web server. Example:
268     #   ActionController::Base.asset_host = "http://assets.example.com"
269     @@asset_host = ""
270     cattr_accessor :asset_host
272     # All requests are considered local by default, so everyone will be exposed to detailed debugging screens on errors.
273     # When the application is ready to go public, this should be set to false, and the protected method <tt>local_request?</tt>
274     # should instead be implemented in the controller to determine when debugging screens should be shown.
275     @@consider_all_requests_local = true
276     cattr_accessor :consider_all_requests_local
278     # Enable or disable the collection of failure information for RoutingErrors.
279     # This information can be extremely useful when tweaking custom routes, but is
280     # pointless once routes have been tested and verified.
281     @@debug_routes = true
282     cattr_accessor :debug_routes
284     # Controls whether the application is thread-safe, so multi-threaded servers like WEBrick know whether to apply a mutex
285     # around the performance of each action. Action Pack and Active Record are by default thread-safe, but many applications
286     # may not be. Turned off by default.
287     @@allow_concurrency = false
288     cattr_accessor :allow_concurrency
290     # Modern REST web services often need to submit complex data to the web application.
291     # The param_parsers hash lets you register handlers which will process the http body and add parameters to the
292     # <tt>params</tt> hash. These handlers are invoked for post and put requests.
293     #
294     # By default application/xml is enabled. A XmlSimple class with the same param name as the root will be instanciated
295     # in the <tt>params</tt>. This allows XML requests to mask themselves as regular form submissions, so you can have one
296     # action serve both regular forms and web service requests.
297     #
298     # Example of doing your own parser for a custom content type:
299     #
300     #   ActionController::Base.param_parsers[Mime::Type.lookup('application/atom+xml')] = Proc.new do |data|
301     #      node = REXML::Document.new(post)
302     #     { node.root.name => node.root }
303     #   end
304     #
305     # Note: Up until release 1.1 of Rails, Action Controller would default to using XmlSimple configured to discard the
306     # root node for such requests. The new default is to keep the root, such that "<r><name>David</name></r>" results
307     # in params[:r][:name] for "David" instead of params[:name]. To get the old behavior, you can
308     # re-register XmlSimple as application/xml handler ike this:
309     #
310     #   ActionController::Base.param_parsers[Mime::XML] =
311     #     Proc.new { |data| XmlSimple.xml_in(data, 'ForceArray' => false) }
312     #
313     # A YAML parser is also available and can be turned on with:
314     #
315     #   ActionController::Base.param_parsers[Mime::YAML] = :yaml
316     @@param_parsers = { Mime::MULTIPART_FORM => :multipart_form,
317                         Mime::URL_ENCODED_FORM => :url_encoded_form,
318                         Mime::XML => :xml_simple }
319     cattr_accessor :param_parsers
321     # Controls the default charset for all renders.
322     @@default_charset = "utf-8"
323     cattr_accessor :default_charset
324     
325     # The logger is used for generating information on the action run-time (including benchmarking) if available.
326     # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
327     cattr_accessor :logger
329     # Determines which template class should be used by ActionController.
330     cattr_accessor :template_class
332     # Turn on +ignore_missing_templates+ if you want to unit test actions without making the associated templates.
333     cattr_accessor :ignore_missing_templates
335     # Controls the resource action separator
336     @@resource_action_separator = "/"
337     cattr_accessor :resource_action_separator
338     
339     # Sets the token parameter name for RequestForgery.  Calling #protect_from_forgery sets it to :authenticity_token by default
340     cattr_accessor :request_forgery_protection_token
342     # Indicates whether or not optimise the generated named
343     # route helper methods
344     cattr_accessor :optimise_named_routes
345     self.optimise_named_routes = true
347     # Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
348     class_inheritable_accessor :allow_forgery_protection
349     self.allow_forgery_protection = true
351     # Holds the request object that's primarily used to get environment variables through access like
352     # <tt>request.env["REQUEST_URI"]</tt>.
353     attr_internal :request
355     # Holds a hash of all the GET, POST, and Url parameters passed to the action. Accessed like <tt>params["post_id"]</tt>
356     # to get the post_id. No type casts are made, so all values are returned as strings.
357     attr_internal :params
359     # Holds the response object that's primarily used to set additional HTTP headers through access like
360     # <tt>response.headers["Cache-Control"] = "no-cache"</tt>. Can also be used to access the final body HTML after a template
361     # has been rendered through response.body -- useful for <tt>after_filter</tt>s that wants to manipulate the output,
362     # such as a OutputCompressionFilter.
363     attr_internal :response
365     # Holds a hash of objects in the session. Accessed like <tt>session[:person]</tt> to get the object tied to the "person"
366     # key. The session will hold any type of object as values, but the key should be a string or symbol.
367     attr_internal :session
369     # Holds a hash of header names and values. Accessed like <tt>headers["Cache-Control"]</tt> to get the value of the Cache-Control
370     # directive. Values should always be specified as strings.
371     attr_internal :headers
373     # Holds the hash of variables that are passed on to the template class to be made available to the view. This hash
374     # is generated by taking a snapshot of all the instance variables in the current scope just before a template is rendered.
375     attr_accessor :assigns
377     # Returns the name of the action this controller is processing.
378     attr_accessor :action_name
380     # Templates that are exempt from layouts
381     @@exempt_from_layout = Set.new([/\.rjs$/])
383     class << self
384       # Factory for the standard create, process loop where the controller is discarded after processing.
385       def process(request, response) #:nodoc:
386         new.process(request, response)
387       end
389       # Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController".
390       def controller_class_name
391         @controller_class_name ||= name.demodulize
392       end
394       # Converts the class name from something like "OneModule::TwoModule::NeatController" to "neat".
395       def controller_name
396         @controller_name ||= controller_class_name.sub(/Controller$/, '').underscore
397       end
399       # Converts the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".
400       def controller_path
401         @controller_path ||= name.gsub(/Controller$/, '').underscore
402       end
404       # Return an array containing the names of public methods that have been marked hidden from the action processor.
405       # By default, all methods defined in ActionController::Base and included modules are hidden.
406       # More methods can be hidden using <tt>hide_actions</tt>.
407       def hidden_actions
408         unless read_inheritable_attribute(:hidden_actions)
409           write_inheritable_attribute(:hidden_actions, ActionController::Base.public_instance_methods.map(&:to_s))
410         end
412         read_inheritable_attribute(:hidden_actions)
413       end
415       # Hide each of the given methods from being callable as actions.
416       def hide_action(*names)
417         write_inheritable_attribute(:hidden_actions, hidden_actions | names.map(&:to_s))
418       end
420       ## View load paths determine the bases from which template references can be made. So a call to
421       ## render("test/template") will be looked up in the view load paths array and the closest match will be
422       ## returned.
423       def view_paths
424         @view_paths || superclass.view_paths
425       end
427       def view_paths=(value)
428         @view_paths = value
429       end
431       # Adds a view_path to the front of the view_paths array.
432       # If the current class has no view paths, copy them from 
433       # the superclass
434       #
435       #   ArticleController.prepend_view_path("views/default")
436       #   ArticleController.prepend_view_path(["views/default", "views/custom"])
437       #
438       def prepend_view_path(path)
439         @view_paths = superclass.view_paths.dup if @view_paths.nil?
440         view_paths.unshift(*path)
441       end
442       
443       # Adds a view_path to the end of the view_paths array.
444       # If the current class has no view paths, copy them from 
445       # the superclass
446       #
447       #   ArticleController.append_view_path("views/default")
448       #   ArticleController.append_view_path(["views/default", "views/custom"])
449       #
450       def append_view_path(path)
451         @view_paths = superclass.view_paths.dup if @view_paths.nil?
452         view_paths.push(*path)
453       end
454       
455       # Replace sensitive paramater data from the request log.
456       # Filters paramaters that have any of the arguments as a substring.
457       # Looks in all subhashes of the param hash for keys to filter.
458       # If a block is given, each key and value of the paramater hash and all
459       # subhashes is passed to it, the value or key
460       # can be replaced using String#replace or similar method.
461       #
462       # Examples:
463       #   filter_parameter_logging
464       #   => Does nothing, just slows the logging process down
465       #
466       #   filter_parameter_logging :password
467       #   => replaces the value to all keys matching /password/i with "[FILTERED]"
468       #
469       #   filter_parameter_logging :foo, "bar"
470       #   => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
471       #
472       #   filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
473       #   => reverses the value to all keys matching /secret/i
474       #
475       #   filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
476       #   => reverses the value to all keys matching /secret/i, and
477       #      replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
478       def filter_parameter_logging(*filter_words, &block)
479         parameter_filter = Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true) if filter_words.length > 0
481         define_method(:filter_parameters) do |unfiltered_parameters|
482           filtered_parameters = {}
484           unfiltered_parameters.each do |key, value|
485             if key =~ parameter_filter
486               filtered_parameters[key] = '[FILTERED]'
487             elsif value.is_a?(Hash)
488               filtered_parameters[key] = filter_parameters(value)
489             elsif block_given?
490               key = key.dup
491               value = value.dup if value
492               yield key, value
493               filtered_parameters[key] = value
494             else
495               filtered_parameters[key] = value
496             end
497           end
499           filtered_parameters
500         end
501       end
503       # Don't render layouts for templates with the given extensions.
504       def exempt_from_layout(*extensions)
505         regexps = extensions.collect do |extension|
506           extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
507         end
508         @@exempt_from_layout.merge regexps
509       end
510     end
512     public
513       # Extracts the action_name from the request parameters and performs that action.
514       def process(request, response, method = :perform_action, *arguments) #:nodoc:
515         initialize_template_class(response)
516         assign_shortcuts(request, response)
517         initialize_current_url
518         assign_names
519         forget_variables_added_to_assigns
521         log_processing
522         send(method, *arguments)
524         assign_default_content_type_and_charset
526         response.request = request
527         response.prepare! unless component_request?
528         response
529       ensure
530         process_cleanup
531       end
533       # Returns a URL that has been rewritten according to the options hash and the defined Routes.
534       # (For doing a complete redirect, use redirect_to).
535       # Â 
536       # <tt>url_for</tt> is used to:
537       # Â 
538       # All keys given to url_for are forwarded to the Route module, save for the following:
539       # * <tt>:anchor</tt> -- specifies the anchor name to be appended to the path. For example,
540       #   <tt>url_for :controller => 'posts', :action => 'show', :id => 10, :anchor => 'comments'</tt>
541       #   will produce "/posts/show/10#comments".
542       # * <tt>:only_path</tt> --  if true, returns the relative URL (omitting the protocol, host name, and port) (<tt>false</tt> by default)
543       # * <tt>:trailing_slash</tt> --  if true, adds a trailing slash, as in "/archive/2005/". Note that this
544       #   is currently not recommended since it breaks caching.
545       # * <tt>:host</tt> -- overrides the default (current) host if provided.
546       # * <tt>:protocol</tt> -- overrides the default (current) protocol if provided.
547       # * <tt>:port</tt> -- optionally specify the port to connect to.
548       # * <tt>:user</tt> -- Inline HTTP authentication (only plucked out if :password is also present).
549       # * <tt>:password</tt> -- Inline HTTP authentication (only plucked out if :user is also present).
550       # * <tt>:skip_relative_url_root</tt> -- if true, the url is not constructed using the relative_url_root of the request so the path
551       #   will include the web server relative installation directory.
552       #
553       # The URL is generated from the remaining keys in the hash. A URL contains two key parts: the <base> and a query string.
554       # Routes composes a query string as the key/value pairs not included in the <base>.
555       #
556       # The default Routes setup supports a typical Rails path of "controller/action/id" where action and id are optional, with
557       # action defaulting to 'index' when not given. Here are some typical url_for statements and their corresponding URLs:
558       #
559       #   url_for :controller => 'posts', :action => 'recent'                # => 'proto://host.com/posts/recent'
560       #   url_for :controller => 'posts', :action => 'index'                 # => 'proto://host.com/posts'
561       #   url_for :controller => 'posts', :action => 'index', :port=>'8033'  # => 'proto://host.com:8033/posts'
562       #   url_for :controller => 'posts', :action => 'show', :id => 10       # => 'proto://host.com/posts/show/10'
563       #   url_for :controller => 'posts', :user => 'd', :password => '123'   # => 'proto://d:123@host.com/posts'
564       #
565       # When generating a new URL, missing values may be filled in from the current request's parameters. For example,
566       # <tt>url_for :action => 'some_action'</tt> will retain the current controller, as expected. This behavior extends to
567       # other parameters, including <tt>:controller</tt>, <tt>:id</tt>, and any other parameters that are placed into a Route's
568       # path.
569       # Â 
570       # The URL helpers such as <tt>url_for</tt> have a limited form of memory: when generating a new URL, they can look for
571       # missing values in the current request's parameters. Routes attempts to guess when a value should and should not be
572       # taken from the defaults. There are a few simple rules on how this is performed:
573       #
574       # * If the controller name begins with a slash, no defaults are used: <tt>url_for :controller => '/home'</tt>
575       # * If the controller changes, the action will default to index unless provided
576       #
577       # The final rule is applied while the URL is being generated and is best illustrated by an example. Let us consider the
578       # route given by <tt>map.connect 'people/:last/:first/:action', :action => 'bio', :controller => 'people'</tt>.
579       #
580       # Suppose that the current URL is "people/hh/david/contacts". Let's consider a few different cases of URLs which are generated
581       # from this page.
582       #
583       # * <tt>url_for :action => 'bio'</tt> -- During the generation of this URL, default values will be used for the first and
584       # last components, and the action shall change. The generated URL will be, "people/hh/david/bio".
585       # * <tt>url_for :first => 'davids-little-brother'</tt> This generates the URL 'people/hh/davids-little-brother' -- note
586       #   that this URL leaves out the assumed action of 'bio'.
587       #
588       # However, you might ask why the action from the current request, 'contacts', isn't carried over into the new URL. The
589       # answer has to do with the order in which the parameters appear in the generated path. In a nutshell, since the
590       # value that appears in the slot for <tt>:first</tt> is not equal to default value for <tt>:first</tt> we stop using
591       # defaults. On it's own, this rule can account for much of the typical Rails URL behavior.
592       # Â 
593       # Although a convenience, defaults can occasionally get in your way. In some cases a default persists longer than desired.
594       # The default may be cleared by adding <tt>:name => nil</tt> to <tt>url_for</tt>'s options.
595       # This is often required when writing form helpers, since the defaults in play may vary greatly depending upon where the
596       # helper is used from. The following line will redirect to PostController's default action, regardless of the page it is
597       # displayed on:
598       #
599       #   url_for :controller => 'posts', :action => nil
600       #
601       # If you explicitly want to create a URL that's almost the same as the current URL, you can do so using the
602       # :overwrite_params options. Say for your posts you have different views for showing and printing them.
603       # Then, in the show view, you get the URL for the print view like this
604       #
605       #   url_for :overwrite_params => { :action => 'print' }
606       #
607       # This takes the current URL as is and only exchanges the action. In contrast, <tt>url_for :action => 'print'</tt>
608       # would have slashed-off the path components after the changed action.
609       def url_for(options = nil) #:doc:
610         case options || {}
611           when String
612             options
613           when Hash
614             @url.rewrite(rewrite_options(options))
615           else
616             polymorphic_url(options)
617         end
618       end
620       # Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController".
621       def controller_class_name
622         self.class.controller_class_name
623       end
625       # Converts the class name from something like "OneModule::TwoModule::NeatController" to "neat".
626       def controller_name
627         self.class.controller_name
628       end
630       # Converts the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".
631       def controller_path
632         self.class.controller_path
633       end
635       def session_enabled?
636         request.session_options && request.session_options[:disabled] != false
637       end
639       
640       self.view_paths = []
641       
642       # View load paths for controller.
643       def view_paths
644         (@template || self.class).view_paths
645       end
646     
647       def view_paths=(value)
648         (@template || self.class).view_paths = value
649       end
650       
651     protected
652       # Renders the content that will be returned to the browser as the response body.
653       #
654       # === Rendering an action
655       #
656       # Action rendering is the most common form and the type used automatically by Action Controller when nothing else is
657       # specified. By default, actions are rendered within the current layout (if one exists).
658       #
659       #   # Renders the template for the action "goal" within the current controller
660       #   render :action => "goal"
661       #
662       #   # Renders the template for the action "short_goal" within the current controller,
663       #   # but without the current active layout
664       #   render :action => "short_goal", :layout => false
665       #
666       #   # Renders the template for the action "long_goal" within the current controller,
667       #   # but with a custom layout
668       #   render :action => "long_goal", :layout => "spectacular"
669       #
670       # === Rendering partials
671       #
672       # Partial rendering in a controller is most commonly used together with Ajax calls that only update one or a few elements on a page
673       # without reloading. Rendering of partials from the controller makes it possible to use the same partial template in
674       # both the full-page rendering (by calling it from within the template) and when sub-page updates happen (from the
675       # controller action responding to Ajax calls). By default, the current layout is not used.
676       #
677       #   # Renders the same partial with a local variable.
678       #   render :partial => "person", :locals => { :name => "david" }
679       #
680       #   # Renders the partial, making @new_person available through
681       #   # the local variable 'person'
682       #   render :partial => "person", :object => @new_person
683       #
684       #   # Renders a collection of the same partial by making each element
685       #   # of @winners available through the local variable "person" as it
686       #   # builds the complete response.
687       #   render :partial => "person", :collection => @winners
688       #
689       #   # Renders the same collection of partials, but also renders the
690       #   # person_divider partial between each person partial.
691       #   render :partial => "person", :collection => @winners, :spacer_template => "person_divider"
692       #
693       #   # Renders a collection of partials located in a view subfolder
694       #   # outside of our current controller.  In this example we will be
695       #   # rendering app/views/shared/_note.r(html|xml)  Inside the partial
696       #   # each element of @new_notes is available as the local var "note".
697       #   render :partial => "shared/note", :collection => @new_notes
698       #
699       #   # Renders the partial with a status code of 500 (internal error).
700       #   render :partial => "broken", :status => 500
701       #
702       # Note that the partial filename must also be a valid Ruby variable name,
703       # so e.g. 2005 and register-user are invalid.
704       #
705       #
706       # == Automatic etagging
707       #
708       # Rendering will automatically insert the etag header on 200 OK responses. The etag is calculated using MD5 of the
709       # response body. If a request comes in that has a matching etag, the response will be changed to a 304 Not Modified
710       # and the response body will be set to an empty string. No etag header will be inserted if it's already set.
711       #
712       # === Rendering a template
713       #
714       # Template rendering works just like action rendering except that it takes a path relative to the template root.
715       # The current layout is automatically applied.
716       #
717       #   # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
718       #   render :template => "weblog/show"
719       #
720       # === Rendering a file
721       #
722       # File rendering works just like action rendering except that it takes a filesystem path. By default, the path
723       # is assumed to be absolute, and the current layout is not applied.
724       #
725       #   # Renders the template located at the absolute filesystem path
726       #   render :file => "/path/to/some/template.erb"
727       #   render :file => "c:/path/to/some/template.erb"
728       #
729       #   # Renders a template within the current layout, and with a 404 status code
730       #   render :file => "/path/to/some/template.erb", :layout => true, :status => 404
731       #   render :file => "c:/path/to/some/template.erb", :layout => true, :status => 404
732       #
733       #   # Renders a template relative to the template root and chooses the proper file extension
734       #   render :file => "some/template", :use_full_path => true
735       #
736       # === Rendering text
737       #
738       # Rendering of text is usually used for tests or for rendering prepared content, such as a cache. By default, text
739       # rendering is not done within the active layout.
740       #
741       #   # Renders the clear text "hello world" with status code 200
742       #   render :text => "hello world!"
743       #
744       #   # Renders the clear text "Explosion!"  with status code 500
745       #   render :text => "Explosion!", :status => 500
746       #
747       #   # Renders the clear text "Hi there!" within the current active layout (if one exists)
748       #   render :text => "Explosion!", :layout => true
749       #
750       #   # Renders the clear text "Hi there!" within the layout
751       #   # placed in "app/views/layouts/special.r(html|xml)"
752       #   render :text => "Explosion!", :layout => "special"
753       #
754       # The :text option can also accept a Proc object, which can be used to manually control the page generation. This should
755       # generally be avoided, as it violates the separation between code and content, and because almost everything that can be
756       # done with this method can also be done more cleanly using one of the other rendering methods, most notably templates.
757       #
758       #   # Renders "Hello from code!"
759       #   render :text => proc { |response, output| output.write("Hello from code!") }
760       #
761       # === Rendering JSON
762       #
763       # Rendering JSON sets the content type to application/json and optionally wraps the JSON in a callback. It is expected
764       # that the response will be parsed (or eval'd) for use as a data structure.
765       #
766       #   # Renders '{"name": "David"}'
767       #   render :json => {:name => "David"}.to_json
768       #
769       # It's not necessary to call <tt>to_json</tt> on the object you want to render, since <tt>render</tt> will
770       # automatically do that for you:
771       #
772       #   # Also renders '{"name": "David"}'
773       #   render :json => {:name => "David"}
774       #
775       # Sometimes the result isn't handled directly by a script (such as when the request comes from a SCRIPT tag),
776       # so the <tt>:callback</tt> option is provided for these cases.
777       #
778       #   # Renders 'show({"name": "David"})'
779       #   render :json => {:name => "David"}.to_json, :callback => 'show'
780       #
781       # === Rendering an inline template
782       #
783       # Rendering of an inline template works as a cross between text and action rendering where the source for the template
784       # is supplied inline, like text, but its interpreted with ERb or Builder, like action. By default, ERb is used for rendering
785       # and the current layout is not used.
786       #
787       #   # Renders "hello, hello, hello, again"
788       #   render :inline => "<%= 'hello, ' * 3 + 'again' %>"
789       #
790       #   # Renders "<p>Good seeing you!</p>" using Builder
791       #   render :inline => "xml.p { 'Good seeing you!' }", :type => :builder
792       #
793       #   # Renders "hello david"
794       #   render :inline => "<%= 'hello ' + name %>", :locals => { :name => "david" }
795       #
796       # === Rendering inline JavaScriptGenerator page updates
797       #
798       # In addition to rendering JavaScriptGenerator page updates with Ajax in RJS templates (see ActionView::Base for details),
799       # you can also pass the <tt>:update</tt> parameter to +render+, along with a block, to render page updates inline.
800       #
801       #   render :update do |page|
802       #     page.replace_html  'user_list', :partial => 'user', :collection => @users
803       #     page.visual_effect :highlight, 'user_list'
804       #   end
805       #
806       # === Rendering with status and location headers
807       #
808       # All renders take the :status and :location options and turn them into headers. They can even be used together:
809       #
810       #   render :xml => post.to_xml, :status => :created, :location => post_url(post)
811       def render(options = nil, &block) #:doc:
812         raise DoubleRenderError, "Can only render or redirect once per action" if performed?
814         if options.nil?
815           return render_for_file(default_template_name, nil, true)
816         else
817           if options == :update
818             options = { :update => true }
819           elsif !options.is_a?(Hash)
820             raise RenderError, "You called render with invalid options : #{options}"
821           end
822         end
824         if content_type = options[:content_type]
825           response.content_type = content_type.to_s
826         end
828         if location = options[:location]
829           response.headers["Location"] = url_for(location)
830         end
832         if text = options[:text]
833           render_for_text(text, options[:status])
835         else
836           if file = options[:file]
837             render_for_file(file, options[:status], options[:use_full_path], options[:locals] || {})
839           elsif template = options[:template]
840             render_for_file(template, options[:status], true)
842           elsif inline = options[:inline]
843             add_variables_to_assigns
844             render_for_text(@template.render_template(options[:type] || :erb, inline, nil, options[:locals] || {}), options[:status])
846           elsif action_name = options[:action]
847             template = default_template_name(action_name.to_s)
848             if options[:layout] && !template_exempt_from_layout?(template)
849               render_with_a_layout(:file => template, :status => options[:status], :use_full_path => true, :layout => true)              
850             else
851               render_with_no_layout(:file => template, :status => options[:status], :use_full_path => true)
852             end            
854           elsif xml = options[:xml]
855             response.content_type = Mime::XML
856             render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml, options[:status])
858           elsif json = options[:json]
859             json = json.to_json unless json.is_a?(String)
860             json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
861             response.content_type = Mime::JSON
862             render_for_text(json, options[:status])
864           elsif partial = options[:partial]
865             partial = default_template_name if partial == true
866             add_variables_to_assigns
868             if collection = options[:collection]
869               render_for_text(
870                 @template.send!(:render_partial_collection, partial, collection, 
871                 options[:spacer_template], options[:locals]), options[:status]
872               )
873             else
874               render_for_text(
875                 @template.send!(:render_partial, partial, 
876                 ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]), options[:status]
877               )
878             end
880           elsif options[:update]
881             add_variables_to_assigns
882             @template.send! :evaluate_assigns
884             generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
885             response.content_type = Mime::JS
886             render_for_text(generator.to_s)
888           elsif options[:nothing]
889             # Safari doesn't pass the headers of the return if the response is zero length
890             render_for_text(" ", options[:status])
892           else
893             render_for_file(default_template_name, options[:status], true)
894           end
895         end
896       end
898       # Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
899       # of sending it as the response body to the browser.
900       def render_to_string(options = nil, &block) #:doc:
901         render(options, &block)
902       ensure
903         erase_render_results
904         forget_variables_added_to_assigns
905         reset_variables_added_to_assigns
906       end
908       # Return a response that has no content (merely headers). The options
909       # argument is interpreted to be a hash of header names and values.
910       # This allows you to easily return a response that consists only of
911       # significant headers:
912       #
913       #   head :created, :location => person_path(@person)
914       #
915       # It can also be used to return exceptional conditions:
916       #
917       #   return head(:method_not_allowed) unless request.post?
918       #   return head(:bad_request) unless valid_request?
919       #   render
920       def head(*args)
921         if args.length > 2
922           raise ArgumentError, "too many arguments to head"
923         elsif args.empty?
924           raise ArgumentError, "too few arguments to head"
925         elsif args.length == 2
926           status = args.shift
927           options = args.shift
928         elsif args.first.is_a?(Hash)
929           options = args.first
930         else
931           status = args.first
932           options = {}
933         end
935         raise ArgumentError, "head requires an options hash" if !options.is_a?(Hash)
937         status = interpret_status(status || options.delete(:status) || :ok)
939         options.each do |key, value|
940           headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
941         end
943         render :nothing => true, :status => status
944       end
947       # Clears the rendered results, allowing for another render to be performed.
948       def erase_render_results #:nodoc:
949         response.body = nil
950         @performed_render = false
951       end
953       # Clears the redirected results from the headers, resets the status to 200 and returns
954       # the URL that was used to redirect or nil if there was no redirected URL
955       # Note that +redirect_to+ will change the body of the response to indicate a redirection.
956       # The response body is not reset here, see +erase_render_results+
957       def erase_redirect_results #:nodoc:
958         @performed_redirect = false
959         response.redirected_to = nil
960         response.redirected_to_method_params = nil
961         response.headers['Status'] = DEFAULT_RENDER_STATUS_CODE
962         response.headers.delete('Location')
963       end
965       # Erase both render and redirect results
966       def erase_results #:nodoc:
967         erase_render_results
968         erase_redirect_results
969       end
971       def rewrite_options(options) #:nodoc:
972         if defaults = default_url_options(options)
973           defaults.merge(options)
974         else
975           options
976         end
977       end
979       # Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
980       # the form of a hash, just like the one you would use for url_for directly. Example:
981       #
982       #   def default_url_options(options)
983       #     { :project => @project.active? ? @project.url_name : "unknown" }
984       #   end
985       #
986       # As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the
987       # urls as they stem from the business domain. Please note that any individual url_for call can always override the defaults set
988       # by this method.
989       def default_url_options(options) #:doc:
990       end
992       # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
993       #
994       # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
995       # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
996       # * <tt>String starting with protocol:// (like http://)</tt> - Is passed straight through as the target for redirection.
997       # * <tt>String not containing a protocol</tt> - The current protocol and host is prepended to the string.
998       # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
999       #   Short-hand for redirect_to(request.env["HTTP_REFERER"])
1000       #
1001       # Examples:
1002       #   redirect_to :action => "show", :id => 5
1003       #   redirect_to post
1004       #   redirect_to "http://www.rubyonrails.org"
1005       #   redirect_to "/images/screenshot.jpg"
1006       #   redirect_to :back
1007       #
1008       # The redirection happens as a "302 Moved" header unless otherwise specified. 
1009       #
1010       # Examples:
1011       #   redirect_to post_url(@post), :status=>:found
1012       #   redirect_to :action=>'atom', :status=>:moved_permanently
1013       #   redirect_to post_url(@post), :status=>301
1014       #   redirect_to :action=>'atom', :status=>302
1015       #
1016       # When using <tt>redirect_to :back</tt>, if there is no referrer,
1017       # RedirectBackError will be raised. You may specify some fallback
1018       # behavior for this case by rescuing RedirectBackError.
1019       def redirect_to(options = {}, response_status = {}) #:doc: 
1020         
1021         if options.is_a?(Hash) && options[:status] 
1022           status = options.delete(:status) 
1023         elsif response_status[:status] 
1024           status = response_status[:status] 
1025         else 
1026           status = 302 
1027         end
1028         
1029         case options
1030           when %r{^\w+://.*}
1031             raise DoubleRenderError if performed?
1032             logger.info("Redirected to #{options}") if logger && logger.info?
1033             response.redirect(options, interpret_status(status))
1034             response.redirected_to = options
1035             @performed_redirect = true
1037           when String
1038             redirect_to(request.protocol + request.host_with_port + options, :status=>status)
1040           when :back
1041             request.env["HTTP_REFERER"] ? redirect_to(request.env["HTTP_REFERER"], :status=>status) : raise(RedirectBackError)
1043           when Hash
1044             redirect_to(url_for(options), :status=>status)
1045             response.redirected_to = options
1047           else
1048             redirect_to(url_for(options), :status=>status)
1049         end
1050       end
1052       # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that
1053       # intermediate caches shouldn't cache the response.
1054       #
1055       # Examples:
1056       #   expires_in 20.minutes
1057       #   expires_in 3.hours, :private => false
1058       #   expires in 3.hours, 'max-stale' => 5.hours, :private => nil, :public => true
1059       #
1060       # This method will overwrite an existing Cache-Control header.
1061       # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
1062       def expires_in(seconds, options = {}) #:doc:
1063         cache_options = { 'max-age' => seconds, 'private' => true }.symbolize_keys.merge!(options.symbolize_keys)
1064         cache_options.delete_if { |k,v| v.nil? or v == false }
1065         cache_control = cache_options.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"}
1066         response.headers["Cache-Control"] = cache_control.join(', ')
1067       end
1069       # Sets a HTTP 1.1 Cache-Control header of "no-cache" so no caching should occur by the browser or
1070       # intermediate caches (like caching proxy servers).
1071       def expires_now #:doc:
1072         response.headers["Cache-Control"] = "no-cache"
1073       end
1075       # Resets the session by clearing out all the objects stored within and initializing a new session object.
1076       def reset_session #:doc:
1077         request.reset_session
1078         @_session = request.session
1079         response.session = @_session
1080       end
1083     private
1084       def render_for_file(template_path, status = nil, use_full_path = false, locals = {}) #:nodoc:
1085         add_variables_to_assigns
1086         assert_existence_of_template_file(template_path) if use_full_path
1087         logger.info("Rendering #{template_path}" + (status ? " (#{status})" : '')) if logger
1088         render_for_text(@template.render_file(template_path, use_full_path, locals), status)
1089       end
1091       def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
1092         @performed_render = true
1094         response.headers['Status'] = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
1096         if append_response
1097           response.body ||= ''
1098           response.body << text.to_s
1099         else
1100           response.body = text.is_a?(Proc) ? text : text.to_s
1101         end
1102       end
1103       
1104       def initialize_template_class(response)
1105         unless @@template_class
1106           raise "You must assign a template class through ActionController.template_class= before processing a request"
1107         end
1109         response.template = ActionView::Base.new(view_paths, {}, self)
1110         response.template.extend self.class.master_helper_module
1111         response.redirected_to = nil
1112         @performed_render = @performed_redirect = false
1113       end
1115       def assign_shortcuts(request, response)
1116         @_request, @_params, @_cookies = request, request.parameters, request.cookies
1118         @_response         = response
1119         @_response.session = request.session
1121         @_session = @_response.session
1122         @template = @_response.template
1123         @assigns  = @_response.template.assigns
1125         @_headers = @_response.headers
1126       end
1128       def initialize_current_url
1129         @url = UrlRewriter.new(request, params.clone)
1130       end
1132       def log_processing
1133         if logger && logger.info?
1134           logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
1135           logger.info "  Session ID: #{@_session.session_id}" if @_session and @_session.respond_to?(:session_id)
1136           logger.info "  Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(params).inspect : params.inspect}"
1137         end
1138       end
1140       def default_render #:nodoc:
1141         render
1142       end
1144       def perform_action
1145         if self.class.action_methods.include?(action_name)
1146           send(action_name)
1147           default_render unless performed?
1148         elsif respond_to? :method_missing
1149           method_missing action_name
1150           default_render unless performed?
1151         elsif template_exists? && template_public?
1152           default_render
1153         else
1154           raise UnknownAction, "No action responded to #{action_name}", caller
1155         end
1156       end
1158       def performed?
1159         @performed_render || @performed_redirect
1160       end
1162       def assign_names
1163         @action_name = (params['action'] || 'index')
1164       end
1166       def assign_default_content_type_and_charset
1167         response.content_type ||= Mime::HTML
1168         response.charset      ||= self.class.default_charset unless sending_file?
1169       end
1171       def sending_file?
1172         response.headers["Content-Transfer-Encoding"] == "binary"
1173       end
1175       def action_methods
1176         self.class.action_methods
1177       end
1179       def self.action_methods
1180         @action_methods ||= Set.new(public_instance_methods.map(&:to_s)) - hidden_actions
1181       end
1183       def add_variables_to_assigns
1184         unless @variables_added
1185           add_instance_variables_to_assigns
1186           add_class_variables_to_assigns if view_controller_internals
1187           @variables_added = true
1188         end
1189       end
1191       def forget_variables_added_to_assigns
1192         @variables_added = nil
1193       end
1195       def reset_variables_added_to_assigns
1196         @template.instance_variable_set("@assigns_added", nil)
1197       end
1199       def add_instance_variables_to_assigns
1200         @@protected_variables_cache ||= Set.new(protected_instance_variables)
1201         instance_variables.each do |var|
1202           next if @@protected_variables_cache.include?(var)
1203           @assigns[var[1..-1]] = instance_variable_get(var)
1204         end
1205       end
1207       def add_class_variables_to_assigns
1208         %w(view_paths logger template_class ignore_missing_templates).each do |cvar|
1209           @assigns[cvar] = self.send(cvar)
1210         end
1211       end
1213       def protected_instance_variables
1214         if view_controller_internals
1215           %w(@assigns @performed_redirect @performed_render)
1216         else
1217           %w(@assigns @performed_redirect @performed_render
1218              @_request @request @_response @response @_params @params
1219              @_session @session @_cookies @cookies
1220              @template @request_origin @parent_controller)
1221         end
1222       end
1224       def request_origin
1225         # this *needs* to be cached!
1226         # otherwise you'd get different results if calling it more than once
1227         @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}"
1228       end
1230       def complete_request_uri
1231         "#{request.protocol}#{request.host}#{request.request_uri}"
1232       end
1234       def close_session
1235         @_session.close if @_session && @_session.respond_to?(:close)
1236       end
1238       def template_exists?(template_name = default_template_name)
1239         @template.file_exists?(template_name)
1240       end
1242       def template_public?(template_name = default_template_name)
1243         @template.file_public?(template_name)
1244       end
1246       def template_exempt_from_layout?(template_name = default_template_name)
1247         extension = @template && @template.pick_template_extension(template_name)
1248         name_with_extension = !template_name.include?('.') && extension ? "#{template_name}.#{extension}" : template_name
1249         @@exempt_from_layout.any? { |ext| name_with_extension =~ ext }
1250       end
1252       def assert_existence_of_template_file(template_name)
1253         unless template_exists?(template_name) || ignore_missing_templates
1254           full_template_path = template_name.include?('.') ? template_name : "#{template_name}.#{@template.template_format}.erb"
1255           display_paths = view_paths.join(':')
1256           template_type = (template_name =~ /layouts/i) ? 'layout' : 'template'
1257           raise(MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}")
1258         end
1259       end
1261       def default_template_name(action_name = self.action_name)
1262         if action_name
1263           action_name = action_name.to_s
1264           if action_name.include?('/') && template_path_includes_controller?(action_name)
1265             action_name = strip_out_controller(action_name)
1266           end
1267         end
1268         "#{self.class.controller_path}/#{action_name}"
1269       end
1271       def strip_out_controller(path)
1272         path.split('/', 2).last
1273       end
1275       def template_path_includes_controller?(path)
1276         self.class.controller_path.split('/')[-1] == path.split('/')[0]
1277       end
1279       def process_cleanup
1280         close_session
1281       end
1282   end