aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_controller.rb98
-rw-r--r--actionpack/lib/action_controller/abstract.rb10
-rw-r--r--actionpack/lib/action_controller/abstract/base.rb41
-rw-r--r--actionpack/lib/action_controller/abstract/callbacks.rb40
-rw-r--r--actionpack/lib/action_controller/abstract/exceptions.rb3
-rw-r--r--actionpack/lib/action_controller/abstract/helpers.rb59
-rw-r--r--actionpack/lib/action_controller/abstract/layouts.rb82
-rw-r--r--actionpack/lib/action_controller/abstract/logger.rb7
-rw-r--r--actionpack/lib/action_controller/abstract/renderer.rb58
-rw-r--r--actionpack/lib/action_controller/base/base.rb (renamed from actionpack/lib/action_controller/base.rb)559
-rw-r--r--actionpack/lib/action_controller/base/chained/benchmarking.rb (renamed from actionpack/lib/action_controller/benchmarking.rb)2
-rw-r--r--actionpack/lib/action_controller/base/chained/filters.rb (renamed from actionpack/lib/action_controller/filters.rb)0
-rw-r--r--actionpack/lib/action_controller/base/chained/flash.rb (renamed from actionpack/lib/action_controller/flash.rb)0
-rw-r--r--actionpack/lib/action_controller/base/cookies.rb (renamed from actionpack/lib/action_controller/cookies.rb)0
-rw-r--r--actionpack/lib/action_controller/base/helpers.rb (renamed from actionpack/lib/action_controller/helpers.rb)0
-rw-r--r--actionpack/lib/action_controller/base/http_authentication.rb (renamed from actionpack/lib/action_controller/http_authentication.rb)0
-rw-r--r--actionpack/lib/action_controller/base/layout.rb (renamed from actionpack/lib/action_controller/layout.rb)151
-rw-r--r--actionpack/lib/action_controller/base/redirect.rb91
-rw-r--r--actionpack/lib/action_controller/base/render.rb390
-rw-r--r--actionpack/lib/action_controller/base/request_forgery_protection.rb (renamed from actionpack/lib/action_controller/request_forgery_protection.rb)0
-rw-r--r--actionpack/lib/action_controller/base/responder.rb42
-rw-r--r--actionpack/lib/action_controller/base/streaming.rb (renamed from actionpack/lib/action_controller/streaming.rb)0
-rw-r--r--actionpack/lib/action_controller/base/verification.rb (renamed from actionpack/lib/action_controller/verification.rb)0
-rw-r--r--actionpack/lib/action_controller/cgi/ext.rb (renamed from actionpack/lib/action_controller/cgi_ext.rb)6
-rw-r--r--actionpack/lib/action_controller/cgi/ext/cookie.rb (renamed from actionpack/lib/action_controller/cgi_ext/cookie.rb)0
-rw-r--r--actionpack/lib/action_controller/cgi/ext/query_extension.rb (renamed from actionpack/lib/action_controller/cgi_ext/query_extension.rb)0
-rw-r--r--actionpack/lib/action_controller/cgi/ext/stdinput.rb (renamed from actionpack/lib/action_controller/cgi_ext/stdinput.rb)0
-rw-r--r--actionpack/lib/action_controller/cgi/process.rb (renamed from actionpack/lib/action_controller/cgi_process.rb)2
-rw-r--r--actionpack/lib/action_controller/dispatch/dispatcher.rb (renamed from actionpack/lib/action_controller/dispatcher.rb)4
-rw-r--r--actionpack/lib/action_controller/dispatch/middlewares.rb (renamed from actionpack/lib/action_controller/middlewares.rb)6
-rw-r--r--actionpack/lib/action_controller/dispatch/rescue.rb (renamed from actionpack/lib/action_controller/rescue.rb)16
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb (renamed from actionpack/lib/action_controller/templates/rescues/_request_and_response.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb (renamed from actionpack/lib/action_controller/templates/rescues/_trace.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb (renamed from actionpack/lib/action_controller/templates/rescues/diagnostics.erb)5
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb (renamed from actionpack/lib/action_controller/templates/rescues/layout.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb (renamed from actionpack/lib/action_controller/templates/rescues/missing_template.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb (renamed from actionpack/lib/action_controller/templates/rescues/routing_error.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb (renamed from actionpack/lib/action_controller/templates/rescues/template_error.erb)0
-rw-r--r--actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb (renamed from actionpack/lib/action_controller/templates/rescues/unknown_action.erb)0
-rw-r--r--actionpack/lib/action_controller/mime/responds.rb (renamed from actionpack/lib/action_controller/mime_responds.rb)9
-rw-r--r--actionpack/lib/action_controller/new_base.rb7
-rw-r--r--actionpack/lib/action_controller/new_base/base.rb61
-rw-r--r--actionpack/lib/action_controller/new_base/hide_actions.rb31
-rw-r--r--actionpack/lib/action_controller/new_base/layouts.rb37
-rw-r--r--actionpack/lib/action_controller/new_base/renderer.rb62
-rw-r--r--actionpack/lib/action_controller/new_base/url_for.rb40
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb2
-rw-r--r--actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb (renamed from actionpack/lib/action_controller/polymorphic_routes.rb)0
-rw-r--r--actionpack/lib/action_controller/routing/generation/url_rewriter.rb (renamed from actionpack/lib/action_controller/url_rewriter.rb)0
-rw-r--r--actionpack/lib/action_controller/routing/resources.rb (renamed from actionpack/lib/action_controller/resources.rb)0
-rw-r--r--actionpack/lib/action_controller/routing/route_set.rb2
-rw-r--r--actionpack/lib/action_controller/session/management.rb (renamed from actionpack/lib/action_controller/session_management.rb)2
-rw-r--r--actionpack/lib/action_controller/testing/assertions/dom.rb (renamed from actionpack/lib/action_controller/assertions/dom_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/assertions/model.rb (renamed from actionpack/lib/action_controller/assertions/model_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/assertions/response.rb (renamed from actionpack/lib/action_controller/assertions/response_assertions.rb)4
-rw-r--r--actionpack/lib/action_controller/testing/assertions/routing.rb (renamed from actionpack/lib/action_controller/assertions/routing_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/assertions/selector.rb (renamed from actionpack/lib/action_controller/assertions/selector_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/assertions/tag.rb (renamed from actionpack/lib/action_controller/assertions/tag_assertions.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/integration.rb (renamed from actionpack/lib/action_controller/integration.rb)6
-rw-r--r--actionpack/lib/action_controller/testing/performance.rb (renamed from actionpack/lib/action_controller/performance_test.rb)0
-rw-r--r--actionpack/lib/action_controller/testing/process.rb (renamed from actionpack/lib/action_controller/test_process.rb)4
-rw-r--r--actionpack/lib/action_controller/testing/test_case.rb (renamed from actionpack/lib/action_controller/test_case.rb)2
-rw-r--r--actionpack/lib/action_dispatch.rb64
-rw-r--r--actionpack/lib/action_dispatch/http/headers.rb (renamed from actionpack/lib/action_controller/headers.rb)2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb (renamed from actionpack/lib/action_controller/mime_type.rb)14
-rw-r--r--actionpack/lib/action_dispatch/http/mime_types.rb (renamed from actionpack/lib/action_controller/mime_types.rb)0
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb (renamed from actionpack/lib/action_controller/request.rb)48
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb (renamed from actionpack/lib/action_controller/response.rb)2
-rw-r--r--actionpack/lib/action_dispatch/http/status_codes.rb (renamed from actionpack/lib/action_controller/status_codes.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/failsafe.rb (renamed from actionpack/lib/action_controller/failsafe.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb (renamed from actionpack/lib/action_controller/params_parser.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/rewindable_input.rb (renamed from actionpack/lib/action_controller/rewindable_input.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb (renamed from actionpack/lib/action_controller/session/abstract_store.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb (renamed from actionpack/lib/action_controller/session/cookie_store.rb)2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb (renamed from actionpack/lib/action_controller/session/mem_cache_store.rb)2
-rw-r--r--actionpack/lib/action_dispatch/rack.rb3
-rw-r--r--actionpack/lib/action_dispatch/utils/middleware_stack.rb (renamed from actionpack/lib/action_controller/middleware_stack.rb)2
-rw-r--r--actionpack/lib/action_dispatch/utils/uploaded_file.rb (renamed from actionpack/lib/action_controller/uploaded_file.rb)2
-rw-r--r--actionpack/lib/action_view.rb21
-rw-r--r--actionpack/lib/action_view/base.rb94
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb6
-rw-r--r--actionpack/lib/action_view/paths.rb42
-rw-r--r--actionpack/lib/action_view/reloadable_template.rb117
-rw-r--r--actionpack/lib/action_view/render/partials.rb (renamed from actionpack/lib/action_view/partials.rb)184
-rw-r--r--actionpack/lib/action_view/render/rendering.rb114
-rw-r--r--actionpack/lib/action_view/renderable_partial.rb47
-rw-r--r--actionpack/lib/action_view/template/error.rb (renamed from actionpack/lib/action_view/template_error.rb)0
-rw-r--r--actionpack/lib/action_view/template/handler.rb (renamed from actionpack/lib/action_view/template_handler.rb)0
-rw-r--r--actionpack/lib/action_view/template/handlers.rb (renamed from actionpack/lib/action_view/template_handlers.rb)6
-rw-r--r--actionpack/lib/action_view/template/handlers/builder.rb (renamed from actionpack/lib/action_view/template_handlers/builder.rb)0
-rw-r--r--actionpack/lib/action_view/template/handlers/erb.rb (renamed from actionpack/lib/action_view/template_handlers/erb.rb)2
-rw-r--r--actionpack/lib/action_view/template/handlers/rjs.rb (renamed from actionpack/lib/action_view/template_handlers/rjs.rb)2
-rw-r--r--actionpack/lib/action_view/template/inline.rb (renamed from actionpack/lib/action_view/inline_template.rb)0
-rw-r--r--actionpack/lib/action_view/template/partial.rb18
-rw-r--r--actionpack/lib/action_view/template/renderable.rb (renamed from actionpack/lib/action_view/renderable.rb)42
-rw-r--r--actionpack/lib/action_view/template/template.rb (renamed from actionpack/lib/action_view/template.rb)146
-rw-r--r--actionpack/lib/action_view/template/text.rb9
-rw-r--r--actionpack/lib/action_view/test_case.rb19
98 files changed, 1796 insertions, 1165 deletions
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index d03f4cb231..e435bdbae1 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -31,6 +31,8 @@ rescue LoadError
end
end
+require File.join(File.dirname(__FILE__), "action_pack")
+$:.unshift "#{File.dirname(__FILE__)}/action_controller/vendor/rack-1.0"
begin
gem 'rack', '~> 1.0.0'
require 'rack'
@@ -42,75 +44,57 @@ module ActionController
# TODO: Review explicit to see if they will automatically be handled by
# the initilizer if they are really needed.
def self.load_all!
- [Base, CGIHandler, CgiRequest, Request, Response, Http::Headers, UrlRewriter, UrlWriter]
+ [Base, Request, Response, UrlRewriter, UrlWriter]
+ [ActionDispatch::Http::Headers]
end
- autoload :AbstractRequest, 'action_controller/request'
- autoload :Base, 'action_controller/base'
- autoload :Benchmarking, 'action_controller/benchmarking'
+ autoload :Base, 'action_controller/base/base'
+ autoload :Benchmarking, 'action_controller/base/chained/benchmarking'
autoload :Caching, 'action_controller/caching'
- autoload :Cookies, 'action_controller/cookies'
- autoload :Dispatcher, 'action_controller/dispatcher'
- autoload :Failsafe, 'action_controller/failsafe'
- autoload :Filters, 'action_controller/filters'
- autoload :Flash, 'action_controller/flash'
- autoload :Helpers, 'action_controller/helpers'
- autoload :HttpAuthentication, 'action_controller/http_authentication'
- autoload :Integration, 'action_controller/integration'
- autoload :IntegrationTest, 'action_controller/integration'
- autoload :Layout, 'action_controller/layout'
- autoload :MiddlewareStack, 'action_controller/middleware_stack'
- autoload :MimeResponds, 'action_controller/mime_responds'
- autoload :ParamsParser, 'action_controller/params_parser'
- autoload :PolymorphicRoutes, 'action_controller/polymorphic_routes'
+ autoload :Cookies, 'action_controller/base/cookies'
+ autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
+ autoload :Filters, 'action_controller/base/chained/filters'
+ autoload :Flash, 'action_controller/base/chained/flash'
+ autoload :Helpers, 'action_controller/base/helpers'
+ autoload :HttpAuthentication, 'action_controller/base/http_authentication'
+ autoload :Integration, 'action_controller/testing/integration'
+ autoload :IntegrationTest, 'action_controller/testing/integration'
+ autoload :Layout, 'action_controller/base/layout'
+ autoload :MimeResponds, 'action_controller/mime/responds'
+ autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes'
autoload :RecordIdentifier, 'action_controller/record_identifier'
+ autoload :Redirector, 'action_controller/base/redirect'
autoload :Reloader, 'action_controller/reloader'
- autoload :Request, 'action_controller/request'
- autoload :RequestForgeryProtection, 'action_controller/request_forgery_protection'
- autoload :Rescue, 'action_controller/rescue'
- autoload :Resources, 'action_controller/resources'
- autoload :Response, 'action_controller/response'
- autoload :RewindableInput, 'action_controller/rewindable_input'
+ autoload :Renderer, 'action_controller/base/render'
+ autoload :RequestForgeryProtection, 'action_controller/base/request_forgery_protection'
+ autoload :Rescue, 'action_controller/dispatch/rescue'
+ autoload :Resources, 'action_controller/routing/resources'
+ autoload :Responder, 'action_controller/base/responder'
autoload :Routing, 'action_controller/routing'
- autoload :SessionManagement, 'action_controller/session_management'
- autoload :StatusCodes, 'action_controller/status_codes'
- autoload :Streaming, 'action_controller/streaming'
- autoload :TestCase, 'action_controller/test_case'
- autoload :TestProcess, 'action_controller/test_process'
+ autoload :SessionManagement, 'action_controller/session/management'
+ autoload :Streaming, 'action_controller/base/streaming'
+ autoload :TestCase, 'action_controller/testing/test_case'
+ autoload :TestProcess, 'action_controller/testing/process'
autoload :Translation, 'action_controller/translation'
- autoload :UploadedFile, 'action_controller/uploaded_file'
- autoload :UploadedStringIO, 'action_controller/uploaded_file'
- autoload :UploadedTempfile, 'action_controller/uploaded_file'
- autoload :UrlRewriter, 'action_controller/url_rewriter'
- autoload :UrlWriter, 'action_controller/url_rewriter'
- autoload :Verification, 'action_controller/verification'
+ autoload :UrlEncodedPairParser, 'action_controller/dispatch/url_encoded_pair_parser'
+ autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter'
+ autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter'
+ autoload :Verification, 'action_controller/base/verification'
+ autoload :UploadedFile, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedStringIO, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedTempfile, 'action_dispatch/utils/uploaded_file'
module Assertions
- autoload :DomAssertions, 'action_controller/assertions/dom_assertions'
- autoload :ModelAssertions, 'action_controller/assertions/model_assertions'
- autoload :ResponseAssertions, 'action_controller/assertions/response_assertions'
- autoload :RoutingAssertions, 'action_controller/assertions/routing_assertions'
- autoload :SelectorAssertions, 'action_controller/assertions/selector_assertions'
- autoload :TagAssertions, 'action_controller/assertions/tag_assertions'
+ autoload :DomAssertions, 'action_controller/testing/assertions/dom'
+ autoload :ModelAssertions, 'action_controller/testing/assertions/model'
+ autoload :ResponseAssertions, 'action_controller/testing/assertions/response'
+ autoload :RoutingAssertions, 'action_controller/testing/assertions/routing'
+ autoload :SelectorAssertions, 'action_controller/testing/assertions/selector'
+ autoload :TagAssertions, 'action_controller/testing/assertions/tag'
end
-
- module Http
- autoload :Headers, 'action_controller/headers'
- end
-
- module Session
- autoload :AbstractStore, 'action_controller/session/abstract_store'
- autoload :CookieStore, 'action_controller/session/cookie_store'
- autoload :MemCacheStore, 'action_controller/session/mem_cache_store'
- end
-
- # DEPRECATE: Remove CGI support
- autoload :CgiRequest, 'action_controller/cgi_process'
- autoload :CGIHandler, 'action_controller/cgi_process'
end
-autoload :Mime, 'action_controller/mime_type'
-
autoload :HTML, 'action_controller/vendor/html-scanner'
+require 'action_dispatch'
require 'action_view'
diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb
new file mode 100644
index 0000000000..3f5c4a185f
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract.rb
@@ -0,0 +1,10 @@
+module AbstractController
+ autoload :Base, "action_controller/abstract/base"
+ autoload :Callbacks, "action_controller/abstract/callbacks"
+ autoload :Helpers, "action_controller/abstract/helpers"
+ autoload :Layouts, "action_controller/abstract/layouts"
+ autoload :Logger, "action_controller/abstract/logger"
+ autoload :Renderer, "action_controller/abstract/renderer"
+ # === Exceptions
+ autoload :ActionNotFound, "action_controller/abstract/exceptions"
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb
new file mode 100644
index 0000000000..ade7719cc0
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/base.rb
@@ -0,0 +1,41 @@
+module AbstractController
+ class Base
+
+ attr_internal :response_body
+ attr_internal :response_obj
+ attr_internal :action_name
+
+ def self.process(action)
+ new.process(action)
+ end
+
+ def self.inherited(klass)
+ end
+
+ def initialize
+ self.response_obj = {}
+ end
+
+ def process(action_name)
+ unless respond_to_action?(action_name)
+ raise ActionNotFound, "The action '#{action_name}' could not be found"
+ end
+
+ @_action_name = action_name
+ process_action
+ self.response_obj[:body] = self.response_body
+ self
+ end
+
+ private
+
+ def process_action
+ respond_to?(action_name) ? send(action_name) : send(:action_missing, action_name)
+ end
+
+ def respond_to_action?(action_name)
+ respond_to?(action_name) || respond_to?(:action_missing, true)
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb
new file mode 100644
index 0000000000..c8b509081c
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/callbacks.rb
@@ -0,0 +1,40 @@
+module AbstractController
+ module Callbacks
+ setup do
+ include ActiveSupport::NewCallbacks
+ define_callbacks :process_action
+ end
+
+ def process_action
+ _run_process_action_callbacks(action_name) do
+ super
+ end
+ end
+
+ module ClassMethods
+ def _normalize_callback_options(options)
+ if only = options[:only]
+ only = Array(only).map {|o| "action_name == :#{o}"}.join(" || ")
+ options[:per_key] = {:if => only}
+ end
+ if except = options[:except]
+ except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ")
+ options[:per_key] = {:unless => except}
+ end
+ end
+
+ [:before, :after, :around].each do |filter|
+ class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def #{filter}_filter(*names, &blk)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+ _normalize_callback_options(options)
+ names.push(blk) if block_given?
+ names.each do |name|
+ process_action_callback(:#{filter}, name, options)
+ end
+ end
+ RUBY_EVAL
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/exceptions.rb b/actionpack/lib/action_controller/abstract/exceptions.rb
new file mode 100644
index 0000000000..ec4680629b
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/exceptions.rb
@@ -0,0 +1,3 @@
+module AbstractController
+ class ActionNotFound < StandardError ; end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb
new file mode 100644
index 0000000000..1f0b38417b
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/helpers.rb
@@ -0,0 +1,59 @@
+module AbstractController
+ module Helpers
+ depends_on Renderer
+
+ setup do
+ extlib_inheritable_accessor :master_helper_module
+ self.master_helper_module = Module.new
+ end
+
+ # def self.included(klass)
+ # klass.class_eval do
+ # extlib_inheritable_accessor :master_helper_module
+ # self.master_helper_module = Module.new
+ # end
+ # end
+
+ def _action_view
+ @_action_view ||= begin
+ av = super
+ av.helpers.send(:include, master_helper_module)
+ av
+ end
+ end
+
+ module ClassMethods
+ def inherited(klass)
+ klass.master_helper_module = Module.new
+ klass.master_helper_module.__send__ :include, master_helper_module
+
+ super
+ end
+
+ def add_template_helper(mod)
+ master_helper_module.module_eval { include mod }
+ end
+
+ def helper_method(*meths)
+ meths.flatten.each do |meth|
+ master_helper_module.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
+ def #{meth}(*args, &blk)
+ controller.send(%(#{meth}), *args, &blk)
+ end
+ ruby_eval
+ end
+ end
+
+ def helper(*args, &blk)
+ args.flatten.each do |arg|
+ case arg
+ when Module
+ add_template_helper(arg)
+ end
+ end
+ master_helper_module.module_eval(&blk) if block_given?
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb
new file mode 100644
index 0000000000..478b301a26
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/layouts.rb
@@ -0,0 +1,82 @@
+module AbstractController
+ module Layouts
+
+ depends_on Renderer
+
+ module ClassMethods
+ def layout(layout)
+ unless [String, Symbol, FalseClass, NilClass].include?(layout.class)
+ raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
+ end
+
+ @_layout = layout || false # Converts nil to false
+ _write_layout_method
+ end
+
+ def _implied_layout_name
+ name.underscore
+ end
+
+ # Takes the specified layout and creates a _layout method to be called
+ # by _default_layout
+ #
+ # If the specified layout is a:
+ # String:: return the string
+ # Symbol:: call the method specified by the symbol
+ # false:: return nil
+ # none:: If a layout is found in the view paths with the controller's
+ # name, return that string. Otherwise, use the superclass'
+ # layout (which might also be implied)
+ def _write_layout_method
+ case @_layout
+ when String
+ self.class_eval %{def _layout() #{@_layout.inspect} end}
+ when Symbol
+ self.class_eval %{def _layout() #{@_layout} end}
+ when false
+ self.class_eval %{def _layout() end}
+ else
+ self.class_eval %{
+ def _layout
+ if view_paths.find_by_parts?("#{_implied_layout_name}", formats, "layouts")
+ "#{_implied_layout_name}"
+ else
+ super
+ end
+ end
+ }
+ end
+ end
+ end
+
+ def _render_template(template, options)
+ _action_view._render_template_with_layout(template, options[:_layout])
+ end
+
+ private
+
+ def _layout() end # This will be overwritten
+
+ def _layout_for_name(name)
+ unless [String, FalseClass, NilClass].include?(name.class)
+ raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}"
+ end
+
+ name && view_paths.find_by_parts(name, formats, "layouts")
+ end
+
+ def _default_layout(require_layout = false)
+ if require_layout && !_layout
+ raise ArgumentError,
+ "There was no default layout for #{self.class} in #{view_paths.inspect}"
+ end
+
+ begin
+ layout = _layout_for_name(_layout)
+ rescue NameError => e
+ raise NoMethodError,
+ "You specified #{@_layout.inspect} as the layout, but no such method was found"
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb
new file mode 100644
index 0000000000..4117369bd4
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/logger.rb
@@ -0,0 +1,7 @@
+module AbstractController
+ module Logger
+ setup do
+ cattr_accessor :logger
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb
new file mode 100644
index 0000000000..68c3b07b84
--- /dev/null
+++ b/actionpack/lib/action_controller/abstract/renderer.rb
@@ -0,0 +1,58 @@
+require "action_controller/abstract/logger"
+
+module AbstractController
+ module Renderer
+ depends_on AbstractController::Logger
+
+ setup do
+ attr_internal :formats
+
+ extlib_inheritable_accessor :_view_paths
+
+ self._view_paths ||= ActionView::PathSet.new
+ end
+
+ def _action_view
+ @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self)
+ end
+
+ def render(options = {})
+ self.response_body = render_to_string(options)
+ end
+
+ # Raw rendering of a template.
+ # ====
+ # @option _prefix<String> The template's path prefix
+ # @option _layout<String> The relative path to the layout template to use
+ #
+ # :api: plugin
+ def render_to_string(options = {})
+ name = options[:_template_name] || action_name
+
+ template = options[:_template] || view_paths.find_by_parts(name.to_s, formats, options[:_prefix])
+ _render_template(template, options)
+ end
+
+ def _render_template(template, options)
+ _action_view._render_template_with_layout(template)
+ end
+
+ def view_paths() _view_paths end
+
+ module ClassMethods
+
+ def append_view_path(path)
+ self.view_paths << path
+ end
+
+ def view_paths
+ self._view_paths
+ end
+
+ def view_paths=(paths)
+ self._view_paths = paths.is_a?(ActionView::PathSet) ?
+ paths : ActionView::Base.process_view_paths(paths)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base/base.rb
index 0b58c38fb5..aea434ffa0 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base/base.rb
@@ -58,22 +58,6 @@ module ActionController #:nodoc:
end
end
- class DoubleRenderError < ActionControllerError #:nodoc:
- 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\"."
-
- def initialize(message = nil)
- super(message || DEFAULT_MESSAGE)
- end
- end
-
- class RedirectBackError < ActionControllerError #:nodoc:
- 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"].'
-
- def initialize(message = nil)
- super(message || DEFAULT_MESSAGE)
- end
- end
-
class UnknownHttpMethod < ActionControllerError #:nodoc:
end
@@ -247,9 +231,8 @@ module ActionController #:nodoc:
# end
#
class Base
- DEFAULT_RENDER_STATUS_CODE = "200 OK"
- include StatusCodes
+ include ActionDispatch::StatusCodes
cattr_reader :protected_instance_variables
# Controller specific instance variables which will not be accessible inside views.
@@ -301,7 +284,10 @@ module ActionController #:nodoc:
# A YAML parser is also available and can be turned on with:
#
# ActionController::Base.param_parsers[Mime::YAML] = :yaml
- @@param_parsers = {}
+ @@param_parsers = { Mime::MULTIPART_FORM => :multipart_form,
+ Mime::URL_ENCODED_FORM => :url_encoded_form,
+ Mime::XML => :xml_simple,
+ Mime::JSON => :json }
cattr_accessor :param_parsers
# Controls the default charset for all renders.
@@ -381,8 +367,8 @@ module ActionController #:nodoc:
class << self
def call(env)
# HACK: For global rescue to have access to the original request and response
- request = env["action_controller.rescue.request"] ||= Request.new(env)
- response = env["action_controller.rescue.response"] ||= Response.new
+ request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env)
+ response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new
process(request, response)
end
@@ -514,8 +500,8 @@ module ActionController #:nodoc:
def process(request, response, method = :perform_action, *arguments) #:nodoc:
response.request = request
- initialize_template_class(response)
assign_shortcuts(request, response)
+ initialize_template_class(response)
initialize_current_url
assign_names
@@ -678,371 +664,6 @@ module ActionController #:nodoc:
@template.view_paths.push(*path)
end
- protected
- # Renders the content that will be returned to the browser as the response body.
- #
- # === Rendering an action
- #
- # Action rendering is the most common form and the type used automatically by Action Controller when nothing else is
- # specified. By default, actions are rendered within the current layout (if one exists).
- #
- # # Renders the template for the action "goal" within the current controller
- # render :action => "goal"
- #
- # # Renders the template for the action "short_goal" within the current controller,
- # # but without the current active layout
- # render :action => "short_goal", :layout => false
- #
- # # Renders the template for the action "long_goal" within the current controller,
- # # but with a custom layout
- # render :action => "long_goal", :layout => "spectacular"
- #
- # === Rendering partials
- #
- # Partial rendering in a controller is most commonly used together with Ajax calls that only update one or a few elements on a page
- # without reloading. Rendering of partials from the controller makes it possible to use the same partial template in
- # both the full-page rendering (by calling it from within the template) and when sub-page updates happen (from the
- # controller action responding to Ajax calls). By default, the current layout is not used.
- #
- # # Renders the same partial with a local variable.
- # render :partial => "person", :locals => { :name => "david" }
- #
- # # Renders the partial, making @new_person available through
- # # the local variable 'person'
- # render :partial => "person", :object => @new_person
- #
- # # Renders a collection of the same partial by making each element
- # # of @winners available through the local variable "person" as it
- # # builds the complete response.
- # render :partial => "person", :collection => @winners
- #
- # # Renders a collection of partials but with a custom local variable name
- # render :partial => "admin_person", :collection => @winners, :as => :person
- #
- # # Renders the same collection of partials, but also renders the
- # # person_divider partial between each person partial.
- # render :partial => "person", :collection => @winners, :spacer_template => "person_divider"
- #
- # # Renders a collection of partials located in a view subfolder
- # # outside of our current controller. In this example we will be
- # # rendering app/views/shared/_note.r(html|xml) Inside the partial
- # # each element of @new_notes is available as the local var "note".
- # render :partial => "shared/note", :collection => @new_notes
- #
- # # Renders the partial with a status code of 500 (internal error).
- # render :partial => "broken", :status => 500
- #
- # Note that the partial filename must also be a valid Ruby variable name,
- # so e.g. 2005 and register-user are invalid.
- #
- #
- # == Automatic etagging
- #
- # Rendering will automatically insert the etag header on 200 OK responses. The etag is calculated using MD5 of the
- # response body. If a request comes in that has a matching etag, the response will be changed to a 304 Not Modified
- # and the response body will be set to an empty string. No etag header will be inserted if it's already set.
- #
- # === Rendering a template
- #
- # Template rendering works just like action rendering except that it takes a path relative to the template root.
- # The current layout is automatically applied.
- #
- # # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
- # render :template => "weblog/show"
- #
- # # Renders the template with a local variable
- # render :template => "weblog/show", :locals => {:customer => Customer.new}
- #
- # === Rendering a file
- #
- # File rendering works just like action rendering except that it takes a filesystem path. By default, the path
- # is assumed to be absolute, and the current layout is not applied.
- #
- # # Renders the template located at the absolute filesystem path
- # render :file => "/path/to/some/template.erb"
- # render :file => "c:/path/to/some/template.erb"
- #
- # # Renders a template within the current layout, and with a 404 status code
- # render :file => "/path/to/some/template.erb", :layout => true, :status => 404
- # render :file => "c:/path/to/some/template.erb", :layout => true, :status => 404
- #
- # === Rendering text
- #
- # Rendering of text is usually used for tests or for rendering prepared content, such as a cache. By default, text
- # rendering is not done within the active layout.
- #
- # # Renders the clear text "hello world" with status code 200
- # render :text => "hello world!"
- #
- # # Renders the clear text "Explosion!" with status code 500
- # render :text => "Explosion!", :status => 500
- #
- # # Renders the clear text "Hi there!" within the current active layout (if one exists)
- # render :text => "Hi there!", :layout => true
- #
- # # Renders the clear text "Hi there!" within the layout
- # # placed in "app/views/layouts/special.r(html|xml)"
- # render :text => "Hi there!", :layout => "special"
- #
- # === Streaming data and/or controlling the page generation
- #
- # The <tt>:text</tt> option can also accept a Proc object, which can be used to:
- #
- # 1. stream on-the-fly generated data to the browser. Note that you should
- # use the methods provided by ActionController::Steaming instead if you
- # want to stream a buffer or a file.
- # 2. manually control the page generation. This should generally be avoided,
- # as it violates the separation between code and content, and because almost
- # everything that can be done with this method can also be done more cleanly
- # using one of the other rendering methods, most notably templates.
- #
- # Two arguments are passed to the proc, a <tt>response</tt> object and an
- # <tt>output</tt> object. The response object is equivalent to the return
- # value of the ActionController::Base#response method, and can be used to
- # control various things in the HTTP response, such as setting the
- # Content-Type header. The output object is an writable <tt>IO</tt>-like
- # object, so one can call <tt>write</tt> and <tt>flush</tt> on it.
- #
- # The following example demonstrates how one can stream a large amount of
- # on-the-fly generated data to the browser:
- #
- # # Streams about 180 MB of generated data to the browser.
- # render :text => proc { |response, output|
- # 10_000_000.times do |i|
- # output.write("This is line #{i}\n")
- # output.flush
- # end
- # }
- #
- # Another example:
- #
- # # Renders "Hello from code!"
- # render :text => proc { |response, output| output.write("Hello from code!") }
- #
- # === Rendering XML
- #
- # Rendering XML sets the content type to application/xml.
- #
- # # Renders '<name>David</name>'
- # render :xml => {:name => "David"}.to_xml
- #
- # It's not necessary to call <tt>to_xml</tt> on the object you want to render, since <tt>render</tt> will
- # automatically do that for you:
- #
- # # Also renders '<name>David</name>'
- # render :xml => {:name => "David"}
- #
- # === Rendering JSON
- #
- # Rendering JSON sets the content type to application/json and optionally wraps the JSON in a callback. It is expected
- # that the response will be parsed (or eval'd) for use as a data structure.
- #
- # # Renders '{"name": "David"}'
- # render :json => {:name => "David"}.to_json
- #
- # It's not necessary to call <tt>to_json</tt> on the object you want to render, since <tt>render</tt> will
- # automatically do that for you:
- #
- # # Also renders '{"name": "David"}'
- # render :json => {:name => "David"}
- #
- # Sometimes the result isn't handled directly by a script (such as when the request comes from a SCRIPT tag),
- # so the <tt>:callback</tt> option is provided for these cases.
- #
- # # Renders 'show({"name": "David"})'
- # render :json => {:name => "David"}.to_json, :callback => 'show'
- #
- # === Rendering an inline template
- #
- # Rendering of an inline template works as a cross between text and action rendering where the source for the template
- # is supplied inline, like text, but its interpreted with ERb or Builder, like action. By default, ERb is used for rendering
- # and the current layout is not used.
- #
- # # Renders "hello, hello, hello, again"
- # render :inline => "<%= 'hello, ' * 3 + 'again' %>"
- #
- # # Renders "<p>Good seeing you!</p>" using Builder
- # render :inline => "xml.p { 'Good seeing you!' }", :type => :builder
- #
- # # Renders "hello david"
- # render :inline => "<%= 'hello ' + name %>", :locals => { :name => "david" }
- #
- # === Rendering inline JavaScriptGenerator page updates
- #
- # In addition to rendering JavaScriptGenerator page updates with Ajax in RJS templates (see ActionView::Base for details),
- # you can also pass the <tt>:update</tt> parameter to +render+, along with a block, to render page updates inline.
- #
- # render :update do |page|
- # page.replace_html 'user_list', :partial => 'user', :collection => @users
- # page.visual_effect :highlight, 'user_list'
- # end
- #
- # === Rendering vanilla JavaScript
- #
- # In addition to using RJS with render :update, you can also just render vanilla JavaScript with :js.
- #
- # # Renders "alert('hello')" and sets the mime type to text/javascript
- # render :js => "alert('hello')"
- #
- # === Rendering with status and location headers
- # All renders take the <tt>:status</tt> and <tt>:location</tt> options and turn them into headers. They can even be used together:
- #
- # render :xml => post.to_xml, :status => :created, :location => post_url(post)
- def render(options = nil, extra_options = {}, &block) #:doc:
- raise DoubleRenderError, "Can only render or redirect once per action" if performed?
-
- validate_render_arguments(options, extra_options, block_given?)
-
- if options.nil?
- options = { :template => default_template, :layout => true }
- elsif options == :update
- options = extra_options.merge({ :update => true })
- elsif options.is_a?(String) || options.is_a?(Symbol)
- case options.to_s.index('/')
- when 0
- extra_options[:file] = options
- when nil
- extra_options[:action] = options
- else
- extra_options[:template] = options
- end
-
- options = extra_options
- elsif !options.is_a?(Hash)
- extra_options[:partial] = options
- options = extra_options
- end
-
- layout = pick_layout(options)
- response.layout = layout.path_without_format_and_extension if layout
- logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
-
- if content_type = options[:content_type]
- response.content_type = content_type.to_s
- end
-
- if location = options[:location]
- response.headers["Location"] = url_for(location)
- end
-
- if options.has_key?(:text)
- text = layout ? @template.render(options.merge(:text => options[:text], :layout => layout)) : options[:text]
- render_for_text(text, options[:status])
-
- else
- if file = options[:file]
- render_for_file(file, options[:status], layout, options[:locals] || {})
-
- elsif template = options[:template]
- render_for_file(template, options[:status], layout, options[:locals] || {})
-
- elsif inline = options[:inline]
- render_for_text(@template.render(options.merge(:layout => layout)), options[:status])
-
- elsif action_name = options[:action]
- render_for_file(default_template(action_name.to_s), options[:status], layout)
-
- elsif xml = options[:xml]
- response.content_type ||= Mime::XML
- render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml, options[:status])
-
- elsif js = options[:js]
- response.content_type ||= Mime::JS
- render_for_text(js, options[:status])
-
- elsif json = options[:json]
- json = json.to_json unless json.is_a?(String)
- json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
- response.content_type ||= Mime::JSON
- render_for_text(json, options[:status])
-
- elsif options[:partial]
- options[:partial] = default_template_name if options[:partial] == true
- if layout
- render_for_text(@template.render(:text => @template.render(options), :layout => layout), options[:status])
- else
- render_for_text(@template.render(options), options[:status])
- end
-
- elsif options[:update]
- @template.send(:_evaluate_assigns_and_ivars)
-
- generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
- response.content_type = Mime::JS
- render_for_text(generator.to_s, options[:status])
-
- elsif options[:nothing]
- render_for_text(nil, options[:status])
-
- else
- render_for_file(default_template, options[:status], layout)
- end
- end
- end
-
- # Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
- # of sending it as the response body to the browser.
- def render_to_string(options = nil, &block) #:doc:
- render(options, &block)
- response.body
- ensure
- response.content_type = nil
- erase_render_results
- reset_variables_added_to_assigns
- end
-
- # Return a response that has no content (merely headers). The options
- # argument is interpreted to be a hash of header names and values.
- # This allows you to easily return a response that consists only of
- # significant headers:
- #
- # head :created, :location => person_path(@person)
- #
- # It can also be used to return exceptional conditions:
- #
- # return head(:method_not_allowed) unless request.post?
- # return head(:bad_request) unless valid_request?
- # render
- def head(*args)
- if args.length > 2
- raise ArgumentError, "too many arguments to head"
- elsif args.empty?
- raise ArgumentError, "too few arguments to head"
- end
- options = args.extract_options!
- status = interpret_status(args.shift || options.delete(:status) || :ok)
-
- options.each do |key, value|
- headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
- end
-
- render :nothing => true, :status => status
- end
-
- # Clears the rendered results, allowing for another render to be performed.
- def erase_render_results #:nodoc:
- response.body = []
- @performed_render = false
- end
-
- # Clears the redirected results from the headers, resets the status to 200 and returns
- # the URL that was used to redirect or nil if there was no redirected URL
- # Note that +redirect_to+ will change the body of the response to indicate a redirection.
- # The response body is not reset here, see +erase_render_results+
- def erase_redirect_results #:nodoc:
- @performed_redirect = false
- response.redirected_to = nil
- response.redirected_to_method_params = nil
- response.status = DEFAULT_RENDER_STATUS_CODE
- response.headers.delete('Location')
- end
-
- # Erase both render and redirect results
- def erase_results #:nodoc:
- erase_render_results
- erase_redirect_results
- end
-
def rewrite_options(options) #:nodoc:
if defaults = default_url_options(options)
defaults.merge(options)
@@ -1064,73 +685,6 @@ module ActionController #:nodoc:
def default_url_options(options = nil)
end
- # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
- #
- # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
- # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
- # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
- # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
- # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
- # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
- #
- # Examples:
- # redirect_to :action => "show", :id => 5
- # redirect_to post
- # redirect_to "http://www.rubyonrails.org"
- # redirect_to "/images/screenshot.jpg"
- # redirect_to articles_url
- # redirect_to :back
- #
- # The redirection happens as a "302 Moved" header unless otherwise specified.
- #
- # Examples:
- # redirect_to post_url(@post), :status=>:found
- # redirect_to :action=>'atom', :status=>:moved_permanently
- # redirect_to post_url(@post), :status=>301
- # redirect_to :action=>'atom', :status=>302
- #
- # When using <tt>redirect_to :back</tt>, if there is no referrer,
- # RedirectBackError will be raised. You may specify some fallback
- # behavior for this case by rescuing RedirectBackError.
- def redirect_to(options = {}, response_status = {}) #:doc:
- raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
-
- if options.is_a?(Hash) && options[:status]
- status = options.delete(:status)
- elsif response_status[:status]
- status = response_status[:status]
- else
- status = 302
- end
-
- response.redirected_to = options
-
- case options
- # The scheme name consist of a letter followed by any combination of
- # letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
- # characters; and is terminated by a colon (":").
- when %r{^\w[\w\d+.-]*:.*}
- redirect_to_full_url(options, status)
- when String
- redirect_to_full_url(request.protocol + request.host_with_port + options, status)
- when :back
- if referer = request.headers["Referer"]
- redirect_to(referer, :status=>status)
- else
- raise RedirectBackError
- end
- else
- redirect_to_full_url(url_for(options), status)
- end
- end
-
- def redirect_to_full_url(url, status)
- raise DoubleRenderError if performed?
- logger.info("Redirected to #{url}") if logger && logger.info?
- response.redirect(url, interpret_status(status))
- @performed_redirect = true
- end
-
# Sets the etag and/or last_modified on the response and checks it against
# the client request. If the request doesn't match the options provided, the
# request is considered stale and should be generated from scratch. Otherwise,
@@ -1236,40 +790,20 @@ module ActionController #:nodoc:
end
private
- def render_for_file(template_path, status = nil, layout = nil, locals = {}) #:nodoc:
- path = template_path.respond_to?(:path_without_format_and_extension) ? template_path.path_without_format_and_extension : template_path
- logger.info("Rendering #{path}" + (status ? " (#{status})" : '')) if logger
- render_for_text @template.render(:file => template_path, :locals => locals, :layout => layout), status
- end
-
- def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
- @performed_render = true
-
- response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
-
- if append_response
- response.body_parts << text.to_s
- else
- response.body = case text
- when Proc then text
- when nil then [" "] # Safari doesn't pass the headers of the return if the response is zero length
- else [text.to_s]
- end
+ def _process_options(options)
+ if content_type = options[:content_type]
+ response.content_type = content_type.to_s
end
- end
- def validate_render_arguments(options, extra_options, has_block)
- if options && (has_block && options != :update) && !options.is_a?(String) && !options.is_a?(Hash) && !options.is_a?(Symbol)
- raise RenderError, "You called render with invalid options : #{options.inspect}"
+ if location = options[:location]
+ response.headers["Location"] = url_for(location)
end
- if !extra_options.is_a?(Hash)
- raise RenderError, "You called render with invalid options : #{options.inspect}, #{extra_options.inspect}"
- end
+ response.status = interpret_status(options[:status] || DEFAULT_RENDER_STATUS_CODE)
end
def initialize_template_class(response)
- response.template = ActionView::Base.new(self.class.view_paths, {}, self)
+ @template = response.template = ActionView::Base.new(self.class.view_paths, {}, self, formats)
response.template.helpers.send :include, self.class.master_helper_module
response.redirected_to = nil
@performed_render = @performed_redirect = false
@@ -1282,7 +816,6 @@ module ActionController #:nodoc:
@_response.session = request.session
@_session = @_response.session
- @template = @_response.template
@_headers = @_response.headers
end
@@ -1318,23 +851,21 @@ module ActionController #:nodoc:
end
def perform_action
- if action_methods.include?(action_name)
- send(action_name)
- default_render unless performed?
- elsif respond_to? :method_missing
- method_missing action_name
- default_render unless performed?
- else
- begin
- default_render
- rescue ActionView::MissingTemplate => e
- # Was the implicit template missing, or was it another template?
- if e.path == default_template_name
- raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence(:locale => :en)}", caller
- else
- raise e
- end
- end
+ if called = action_methods.include?(action_name)
+ ret = send(action_name)
+ elsif called = respond_to?(:method_missing)
+ ret = method_missing(action_name)
+ end
+
+ return (performed? ? ret : default_render) if called
+
+ begin
+ default_render
+ rescue ActionView::MissingTemplate => e
+ raise e unless e.action_name == action_name
+ # If the path is the same as the action_name, the action is completely missing
+ raise UnknownAction, "No action responded to #{action_name}. Actions: " +
+ "#{action_methods.sort.to_sentence}", caller
end
end
@@ -1347,23 +878,6 @@ module ActionController #:nodoc:
@action_name = (params['action'] || 'index')
end
- # Returns a set of the methods defined as actions in your controller
- def action_methods
- self.class.action_methods
- end
-
- def self.action_methods
- @action_methods ||=
- # All public instance methods of this class, including ancestors
- public_instance_methods(true).map { |m| m.to_s }.to_set -
- # Except for public instance methods of Base and its ancestors
- Base.public_instance_methods(true).map { |m| m.to_s } +
- # Be sure to include shadowed public instance methods of this class
- public_instance_methods(false).map { |m| m.to_s } -
- # And always exclude explicitly hidden actions
- hidden_actions
- end
-
def reset_variables_added_to_assigns
@template.instance_variable_set("@assigns_added", nil)
end
@@ -1379,6 +893,10 @@ module ActionController #:nodoc:
"#{request.protocol}#{request.host}#{request.request_uri}"
end
+ def close_session
+ # @_session.close if @_session && @_session.respond_to?(:close)
+ end
+
def default_template(action_name = self.action_name)
self.view_paths.find_template(default_template_name(action_name), default_template_format)
end
@@ -1390,7 +908,7 @@ module ActionController #:nodoc:
action_name = strip_out_controller(action_name)
end
end
- "#{self.controller_path}/#{action_name}"
+ "#{controller_path}/#{action_name}"
end
def strip_out_controller(path)
@@ -1402,14 +920,15 @@ module ActionController #:nodoc:
end
def process_cleanup
+ close_session
end
end
Base.class_eval do
- [ Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
+ [ Filters, Layout, Renderer, Redirector, Responder, Benchmarking, Rescue, Flash, MimeResponds, Helpers,
Cookies, Caching, Verification, Streaming, SessionManagement,
- HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods,
- RecordIdentifier, RequestForgeryProtection, Translation
+ HttpAuthentication::Basic::ControllerMethods, HttpAuthentication::Digest::ControllerMethods, RecordIdentifier,
+ RequestForgeryProtection, Translation
].each do |mod|
include mod
end
diff --git a/actionpack/lib/action_controller/benchmarking.rb b/actionpack/lib/action_controller/base/chained/benchmarking.rb
index 47377e5fa9..066150f58a 100644
--- a/actionpack/lib/action_controller/benchmarking.rb
+++ b/actionpack/lib/action_controller/base/chained/benchmarking.rb
@@ -64,7 +64,7 @@ module ActionController #:nodoc:
private
def perform_action_with_benchmark
- if logger
+ if logger && logger.info?
ms = [Benchmark.ms { perform_action_without_benchmark }, 0.01].max
logging_view = defined?(@view_runtime)
logging_active_record = Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/base/chained/filters.rb
index 9022b8b279..9022b8b279 100644
--- a/actionpack/lib/action_controller/filters.rb
+++ b/actionpack/lib/action_controller/base/chained/filters.rb
diff --git a/actionpack/lib/action_controller/flash.rb b/actionpack/lib/action_controller/base/chained/flash.rb
index 56ee9c67e2..56ee9c67e2 100644
--- a/actionpack/lib/action_controller/flash.rb
+++ b/actionpack/lib/action_controller/base/chained/flash.rb
diff --git a/actionpack/lib/action_controller/cookies.rb b/actionpack/lib/action_controller/base/cookies.rb
index ca380e98d0..ca380e98d0 100644
--- a/actionpack/lib/action_controller/cookies.rb
+++ b/actionpack/lib/action_controller/base/cookies.rb
diff --git a/actionpack/lib/action_controller/helpers.rb b/actionpack/lib/action_controller/base/helpers.rb
index ba65032f6a..ba65032f6a 100644
--- a/actionpack/lib/action_controller/helpers.rb
+++ b/actionpack/lib/action_controller/base/helpers.rb
diff --git a/actionpack/lib/action_controller/http_authentication.rb b/actionpack/lib/action_controller/base/http_authentication.rb
index b6b5267c66..b6b5267c66 100644
--- a/actionpack/lib/action_controller/http_authentication.rb
+++ b/actionpack/lib/action_controller/base/http_authentication.rb
diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/base/layout.rb
index 6ec0c1b304..88a15aa6ca 100644
--- a/actionpack/lib/action_controller/layout.rb
+++ b/actionpack/lib/action_controller/base/layout.rb
@@ -2,11 +2,7 @@ module ActionController #:nodoc:
module Layout #:nodoc:
def self.included(base)
base.extend(ClassMethods)
- base.class_eval do
- class << self
- alias_method_chain :inherited, :layout
- end
- end
+ base.class_inheritable_accessor :layout_name, :layout_conditions
end
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
@@ -159,123 +155,90 @@ module ActionController #:nodoc:
#
# This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout.
module ClassMethods
+ extend ActiveSupport::Memoizable
+
# If a layout is specified, all rendered actions will have their result rendered
# when the layout <tt>yield</tt>s. This layout can itself depend on instance variables assigned during action
# performance and have access to them as any normal template would.
def layout(template_name, conditions = {}, auto = false)
add_layout_conditions(conditions)
- write_inheritable_attribute(:layout, template_name)
- write_inheritable_attribute(:auto_layout, auto)
+ self.layout_name = template_name
+ end
+
+ def memoized_default_layout(formats) #:nodoc:
+ self.layout_name || begin
+ layout = default_layout_name
+ layout.is_a?(String) ? find_layout(layout, formats) : layout
+ rescue ActionView::MissingTemplate
+ end
+ end
+
+ def default_layout(*args)
+ (@_memoized_default_layout ||= ::ActiveSupport::ConcurrentHash.new)[args] ||= memoized_default_layout(*args)
+ end
+
+ def memoized_find_layout(layout, formats) #:nodoc:
+ return layout if layout.nil? || layout.respond_to?(:render)
+ prefix = layout.to_s =~ /layouts\// ? nil : "layouts"
+ view_paths.find_by_parts(layout.to_s, formats, prefix)
end
- def layout_conditions #:nodoc:
- @layout_conditions ||= read_inheritable_attribute(:layout_conditions)
+ def find_layout(*args)
+ (@_memoized_find_layout ||= ::ActiveSupport::ConcurrentHash.new)[args] ||= memoized_find_layout(*args)
end
def layout_list #:nodoc:
Array(view_paths).sum([]) { |path| Dir["#{path.to_str}/layouts/**/*"] }
end
+ memoize :layout_list
- private
- def inherited_with_layout(child)
- inherited_without_layout(child)
- unless child.name.blank?
- layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers\//, '')
- child.layout(layout_match, {}, true) unless child.layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
- end
+ def default_layout_name
+ layout_match = name.underscore.sub(/_controller$/, '')
+ if layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
+ superclass.default_layout_name if superclass.respond_to?(:default_layout_name)
+ else
+ layout_match
end
+ end
+ memoize :default_layout_name
+ private
def add_layout_conditions(conditions)
- write_inheritable_hash(:layout_conditions, normalize_conditions(conditions))
- end
-
- def normalize_conditions(conditions)
- conditions.inject({}) {|hash, (key, value)| hash.merge(key => [value].flatten.map {|action| action.to_s})}
+ # :except => :foo == :except => [:foo] == :except => "foo" == :except => ["foo"]
+ conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
+ write_inheritable_hash(:layout_conditions, conditions)
end
end
-
- # Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
- # is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
- # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
- # weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
- def active_layout(passed_layout = nil, options = {})
- layout = passed_layout || default_layout
- return layout if layout.respond_to?(:render)
-
- active_layout = case layout
- when Symbol then __send__(layout)
- when Proc then layout.call(self)
- else layout
+
+ def active_layout(name)
+ name = self.class.default_layout(formats) if name == true
+
+ layout_name = case name
+ when Symbol then __send__(name)
+ when Proc then name.call(self)
+ else name
end
- find_layout(active_layout, default_template_format, options[:html_fallback]) if active_layout
+ self.class.find_layout(layout_name, formats)
end
- private
- def default_layout #:nodoc:
- layout = self.class.read_inheritable_attribute(:layout)
- return layout unless self.class.read_inheritable_attribute(:auto_layout)
- find_layout(layout, default_template_format)
- rescue ActionView::MissingTemplate
- nil
- end
-
- def find_layout(layout, format, html_fallback=false) #:nodoc:
- view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", format, html_fallback)
- rescue ActionView::MissingTemplate
- raise if Mime::Type.lookup_by_extension(format.to_s).html?
- end
-
- def pick_layout(options)
- if options.has_key?(:layout)
- case layout = options.delete(:layout)
- when FalseClass
- nil
- when NilClass, TrueClass
- active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name)
- else
- active_layout(layout, :html_fallback => true)
- end
- else
- active_layout if action_has_layout? && candidate_for_layout?(options)
- end
- end
+ def _pick_layout(layout_name, implicit = false)
+ return unless layout_name || implicit
+ layout_name = true if layout_name.nil?
+ active_layout(layout_name) if action_has_layout? && layout_name
+ end
+ private
def action_has_layout?
if conditions = self.class.layout_conditions
- case
- when only = conditions[:only]
- only.include?(action_name)
- when except = conditions[:except]
- !except.include?(action_name)
- else
- true
+ if only = conditions[:only]
+ return only.include?(action_name)
+ elsif except = conditions[:except]
+ return !except.include?(action_name)
end
- else
- true
end
+ true
end
- def candidate_for_layout?(options)
- template = options[:template] || default_template(options[:action])
- if options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty?
- begin
- template_object = self.view_paths.find_template(template, default_template_format)
- # this restores the behavior from 2.2.2, where response.template.template_format was reset
- # to :html for :js requests with a matching html template.
- # see v2.2.2, ActionView::Base, lines 328-330
- @real_format = :html if response.template.template_format == :js && template_object.format == "html"
- !template_object.exempt_from_layout?
- rescue ActionView::MissingTemplate
- true
- end
- end
- rescue ActionView::MissingTemplate
- false
- end
-
- def default_template_format
- @real_format || response.template.template_format
- end
end
end
diff --git a/actionpack/lib/action_controller/base/redirect.rb b/actionpack/lib/action_controller/base/redirect.rb
new file mode 100644
index 0000000000..2e92117e7c
--- /dev/null
+++ b/actionpack/lib/action_controller/base/redirect.rb
@@ -0,0 +1,91 @@
+module ActionController
+ class RedirectBackError < ActionControllerError #:nodoc:
+ 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"].'
+
+ def initialize(message = nil)
+ super(message || DEFAULT_MESSAGE)
+ end
+ end
+
+ module Redirector
+
+ # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
+ #
+ # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
+ # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
+ # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
+ # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
+ # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
+ # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
+ #
+ # Examples:
+ # redirect_to :action => "show", :id => 5
+ # redirect_to post
+ # redirect_to "http://www.rubyonrails.org"
+ # redirect_to "/images/screenshot.jpg"
+ # redirect_to articles_url
+ # redirect_to :back
+ #
+ # The redirection happens as a "302 Moved" header unless otherwise specified.
+ #
+ # Examples:
+ # redirect_to post_url(@post), :status=>:found
+ # redirect_to :action=>'atom', :status=>:moved_permanently
+ # redirect_to post_url(@post), :status=>301
+ # redirect_to :action=>'atom', :status=>302
+ #
+ # When using <tt>redirect_to :back</tt>, if there is no referrer,
+ # RedirectBackError will be raised. You may specify some fallback
+ # behavior for this case by rescuing RedirectBackError.
+ def redirect_to(options = {}, response_status = {}) #:doc:
+ raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
+
+ if options.is_a?(Hash) && options[:status]
+ status = options.delete(:status)
+ elsif response_status[:status]
+ status = response_status[:status]
+ else
+ status = 302
+ end
+
+ response.redirected_to = options
+
+ case options
+ # The scheme name consist of a letter followed by any combination of
+ # letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
+ # characters; and is terminated by a colon (":").
+ when %r{^\w[\w\d+.-]*:.*}
+ redirect_to_full_url(options, status)
+ when String
+ redirect_to_full_url(request.protocol + request.host_with_port + options, status)
+ when :back
+ if referer = request.headers["Referer"]
+ redirect_to(referer, :status=>status)
+ else
+ raise RedirectBackError
+ end
+ else
+ redirect_to_full_url(url_for(options), status)
+ end
+ end
+
+ def redirect_to_full_url(url, status)
+ raise DoubleRenderError if performed?
+ logger.info("Redirected to #{url}") if logger && logger.info?
+ response.redirect(url, interpret_status(status))
+ @performed_redirect = true
+ end
+
+ # Clears the redirected results from the headers, resets the status to 200 and returns
+ # the URL that was used to redirect or nil if there was no redirected URL
+ # Note that +redirect_to+ will change the body of the response to indicate a redirection.
+ # The response body is not reset here, see +erase_render_results+
+ def erase_redirect_results #:nodoc:
+ @performed_redirect = false
+ response.redirected_to = nil
+ response.redirected_to_method_params = nil
+ response.status = DEFAULT_RENDER_STATUS_CODE
+ response.headers.delete('Location')
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/base/render.rb b/actionpack/lib/action_controller/base/render.rb
new file mode 100644
index 0000000000..c4a3725079
--- /dev/null
+++ b/actionpack/lib/action_controller/base/render.rb
@@ -0,0 +1,390 @@
+module ActionController
+ DEFAULT_RENDER_STATUS_CODE = "200 OK"
+
+ class DoubleRenderError < ActionControllerError #:nodoc:
+ 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\"."
+
+ def initialize(message = nil)
+ super(message || DEFAULT_MESSAGE)
+ end
+ end
+
+ module Renderer
+
+ protected
+ # Renders the content that will be returned to the browser as the response body.
+ #
+ # === Rendering an action
+ #
+ # Action rendering is the most common form and the type used automatically by Action Controller when nothing else is
+ # specified. By default, actions are rendered within the current layout (if one exists).
+ #
+ # # Renders the template for the action "goal" within the current controller
+ # render :action => "goal"
+ #
+ # # Renders the template for the action "short_goal" within the current controller,
+ # # but without the current active layout
+ # render :action => "short_goal", :layout => false
+ #
+ # # Renders the template for the action "long_goal" within the current controller,
+ # # but with a custom layout
+ # render :action => "long_goal", :layout => "spectacular"
+ #
+ # === Rendering partials
+ #
+ # Partial rendering in a controller is most commonly used together with Ajax calls that only update one or a few elements on a page
+ # without reloading. Rendering of partials from the controller makes it possible to use the same partial template in
+ # both the full-page rendering (by calling it from within the template) and when sub-page updates happen (from the
+ # controller action responding to Ajax calls). By default, the current layout is not used.
+ #
+ # # Renders the same partial with a local variable.
+ # render :partial => "person", :locals => { :name => "david" }
+ #
+ # # Renders the partial, making @new_person available through
+ # # the local variable 'person'
+ # render :partial => "person", :object => @new_person
+ #
+ # # Renders a collection of the same partial by making each element
+ # # of @winners available through the local variable "person" as it
+ # # builds the complete response.
+ # render :partial => "person", :collection => @winners
+ #
+ # # Renders a collection of partials but with a custom local variable name
+ # render :partial => "admin_person", :collection => @winners, :as => :person
+ #
+ # # Renders the same collection of partials, but also renders the
+ # # person_divider partial between each person partial.
+ # render :partial => "person", :collection => @winners, :spacer_template => "person_divider"
+ #
+ # # Renders a collection of partials located in a view subfolder
+ # # outside of our current controller. In this example we will be
+ # # rendering app/views/shared/_note.r(html|xml) Inside the partial
+ # # each element of @new_notes is available as the local var "note".
+ # render :partial => "shared/note", :collection => @new_notes
+ #
+ # # Renders the partial with a status code of 500 (internal error).
+ # render :partial => "broken", :status => 500
+ #
+ # Note that the partial filename must also be a valid Ruby variable name,
+ # so e.g. 2005 and register-user are invalid.
+ #
+ #
+ # == Automatic etagging
+ #
+ # Rendering will automatically insert the etag header on 200 OK responses. The etag is calculated using MD5 of the
+ # response body. If a request comes in that has a matching etag, the response will be changed to a 304 Not Modified
+ # and the response body will be set to an empty string. No etag header will be inserted if it's already set.
+ #
+ # === Rendering a template
+ #
+ # Template rendering works just like action rendering except that it takes a path relative to the template root.
+ # The current layout is automatically applied.
+ #
+ # # Renders the template located in [TEMPLATE_ROOT]/weblog/show.r(html|xml) (in Rails, app/views/weblog/show.erb)
+ # render :template => "weblog/show"
+ #
+ # # Renders the template with a local variable
+ # render :template => "weblog/show", :locals => {:customer => Customer.new}
+ #
+ # === Rendering a file
+ #
+ # File rendering works just like action rendering except that it takes a filesystem path. By default, the path
+ # is assumed to be absolute, and the current layout is not applied.
+ #
+ # # Renders the template located at the absolute filesystem path
+ # render :file => "/path/to/some/template.erb"
+ # render :file => "c:/path/to/some/template.erb"
+ #
+ # # Renders a template within the current layout, and with a 404 status code
+ # render :file => "/path/to/some/template.erb", :layout => true, :status => 404
+ # render :file => "c:/path/to/some/template.erb", :layout => true, :status => 404
+ #
+ # === Rendering text
+ #
+ # Rendering of text is usually used for tests or for rendering prepared content, such as a cache. By default, text
+ # rendering is not done within the active layout.
+ #
+ # # Renders the clear text "hello world" with status code 200
+ # render :text => "hello world!"
+ #
+ # # Renders the clear text "Explosion!" with status code 500
+ # render :text => "Explosion!", :status => 500
+ #
+ # # Renders the clear text "Hi there!" within the current active layout (if one exists)
+ # render :text => "Hi there!", :layout => true
+ #
+ # # Renders the clear text "Hi there!" within the layout
+ # # placed in "app/views/layouts/special.r(html|xml)"
+ # render :text => "Hi there!", :layout => "special"
+ #
+ # The <tt>:text</tt> option can also accept a Proc object, which can be used to manually control the page generation. This should
+ # generally be avoided, as it violates the separation between code and content, and because almost everything that can be
+ # done with this method can also be done more cleanly using one of the other rendering methods, most notably templates.
+ #
+ # # Renders "Hello from code!"
+ # render :text => proc { |response, output| output.write("Hello from code!") }
+ #
+ # === Rendering XML
+ #
+ # Rendering XML sets the content type to application/xml.
+ #
+ # # Renders '<name>David</name>'
+ # render :xml => {:name => "David"}.to_xml
+ #
+ # It's not necessary to call <tt>to_xml</tt> on the object you want to render, since <tt>render</tt> will
+ # automatically do that for you:
+ #
+ # # Also renders '<name>David</name>'
+ # render :xml => {:name => "David"}
+ #
+ # === Rendering JSON
+ #
+ # Rendering JSON sets the content type to application/json and optionally wraps the JSON in a callback. It is expected
+ # that the response will be parsed (or eval'd) for use as a data structure.
+ #
+ # # Renders '{"name": "David"}'
+ # render :json => {:name => "David"}.to_json
+ #
+ # It's not necessary to call <tt>to_json</tt> on the object you want to render, since <tt>render</tt> will
+ # automatically do that for you:
+ #
+ # # Also renders '{"name": "David"}'
+ # render :json => {:name => "David"}
+ #
+ # Sometimes the result isn't handled directly by a script (such as when the request comes from a SCRIPT tag),
+ # so the <tt>:callback</tt> option is provided for these cases.
+ #
+ # # Renders 'show({"name": "David"})'
+ # render :json => {:name => "David"}.to_json, :callback => 'show'
+ #
+ # === Rendering an inline template
+ #
+ # Rendering of an inline template works as a cross between text and action rendering where the source for the template
+ # is supplied inline, like text, but its interpreted with ERb or Builder, like action. By default, ERb is used for rendering
+ # and the current layout is not used.
+ #
+ # # Renders "hello, hello, hello, again"
+ # render :inline => "<%= 'hello, ' * 3 + 'again' %>"
+ #
+ # # Renders "<p>Good seeing you!</p>" using Builder
+ # render :inline => "xml.p { 'Good seeing you!' }", :type => :builder
+ #
+ # # Renders "hello david"
+ # render :inline => "<%= 'hello ' + name %>", :locals => { :name => "david" }
+ #
+ # === Rendering inline JavaScriptGenerator page updates
+ #
+ # In addition to rendering JavaScriptGenerator page updates with Ajax in RJS templates (see ActionView::Base for details),
+ # you can also pass the <tt>:update</tt> parameter to +render+, along with a block, to render page updates inline.
+ #
+ # render :update do |page|
+ # page.replace_html 'user_list', :partial => 'user', :collection => @users
+ # page.visual_effect :highlight, 'user_list'
+ # end
+ #
+ # === Rendering vanilla JavaScript
+ #
+ # In addition to using RJS with render :update, you can also just render vanilla JavaScript with :js.
+ #
+ # # Renders "alert('hello')" and sets the mime type to text/javascript
+ # render :js => "alert('hello')"
+ #
+ # === Rendering with status and location headers
+ # All renders take the <tt>:status</tt> and <tt>:location</tt> options and turn them into headers. They can even be used together:
+ #
+ # render :xml => post.to_xml, :status => :created, :location => post_url(post)
+ def render(options = nil, extra_options = {}, &block) #:doc:
+ raise DoubleRenderError, "Can only render or redirect once per action" if performed?
+
+ options = { :layout => true } if options.nil?
+
+ # This handles render "string", render :symbol, and render object
+ # render string and symbol are handled by render_for_name
+ # render object becomes render :partial => object
+ unless options.is_a?(Hash)
+ if options.is_a?(String) || options.is_a?(Symbol)
+ original, options = options, extra_options
+ else
+ extra_options[:partial], options = options, extra_options
+ end
+ end
+
+ layout_name = options.delete(:layout)
+
+ _process_options(options)
+
+ if block_given?
+ @template.send(:_evaluate_assigns_and_ivars)
+
+ generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
+ response.content_type = Mime::JS
+ return render_for_text(generator.to_s)
+ end
+
+ if original
+ return render_for_name(original, layout_name, options) unless block_given?
+ end
+
+ if options.key?(:text)
+ return render_for_text(@template._render_text(options[:text],
+ _pick_layout(layout_name), options))
+ end
+
+ file, template = options.values_at(:file, :template)
+ if file || template
+ file = template.sub(/^\//, '') if template
+ return render_for_file(file, [layout_name, !!template], options)
+ end
+
+ if action_option = options[:action]
+ return render_for_action(action_option, [layout_name, true], options)
+ end
+
+ if inline = options[:inline]
+ render_for_text(@template._render_inline(inline, _pick_layout(layout_name), options))
+
+ elsif xml = options[:xml]
+ response.content_type ||= Mime::XML
+ render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml)
+
+ elsif js = options[:js]
+ response.content_type ||= Mime::JS
+ render_for_text(js)
+
+ elsif json = options[:json]
+ json = json.to_json unless json.is_a?(String)
+ json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
+ response.content_type ||= Mime::JSON
+ render_for_text(json)
+
+ elsif partial = options[:partial]
+ if partial == true
+ parts = [action_name_base, formats, controller_name, true]
+ elsif partial.is_a?(String)
+ parts = partial_parts(partial, options)
+ else
+ return render_for_text(@template._render_partial(options))
+ end
+
+ render_for_parts(parts, layout_name, options)
+
+ elsif options[:nothing]
+ render_for_text(nil)
+
+ else
+ render_for_parts([action_name, formats, controller_path], layout_name, options)
+ end
+ end
+
+ def partial_parts(name, options)
+ segments = name.split("/")
+ parts = segments.pop.split(".")
+
+ case parts.size
+ when 1
+ parts
+ when 2, 3
+ extension = parts.delete_at(1).to_sym
+ if formats.include?(extension)
+ self.formats.replace [extension]
+ end
+ parts.pop if parts.size == 2
+ end
+
+ path = parts.join(".")
+ prefix = segments[0..-1].join("/")
+ prefix = prefix.blank? ? controller_path : prefix
+ parts = [path, formats, prefix]
+ parts.push options[:object] || true
+ end
+
+ def formats
+ @_request.formats.map {|f| f.symbol }.compact
+ end
+
+ def action_name_base(name = action_name)
+ (name.is_a?(String) ? name.sub(/^#{controller_path}\//, '') : name).to_s
+ end
+
+ # Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
+ # of sending it as the response body to the browser.
+ def render_to_string(options = nil, &block) #:doc:
+ render(options, &block)
+ response.body
+ ensure
+ response.content_type = nil
+ erase_render_results
+ reset_variables_added_to_assigns
+ end
+
+ # Clears the rendered results, allowing for another render to be performed.
+ def erase_render_results #:nodoc:
+ response.body = []
+ @performed_render = false
+ end
+
+ # Erase both render and redirect results
+ def erase_results #:nodoc:
+ erase_render_results
+ erase_redirect_results
+ end
+
+ # Return a response that has no content (merely headers). The options
+ # argument is interpreted to be a hash of header names and values.
+ # This allows you to easily return a response that consists only of
+ # significant headers:
+ #
+ # head :created, :location => person_path(@person)
+ #
+ # It can also be used to return exceptional conditions:
+ #
+ # return head(:method_not_allowed) unless request.post?
+ # return head(:bad_request) unless valid_request?
+ # render
+ def head(*args)
+ if args.length > 2
+ raise ArgumentError, "too many arguments to head"
+ elsif args.empty?
+ raise ArgumentError, "too few arguments to head"
+ end
+ options = args.extract_options!
+ status = interpret_status(args.shift || options.delete(:status) || :ok)
+
+ options.each do |key, value|
+ headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
+ end
+
+ render :nothing => true, :status => status
+ end
+
+ private
+ def render_for_name(name, layout, options)
+ case name.to_s.index('/')
+ when 0
+ render_for_file(name, layout, options)
+ when nil
+ render_for_action(name, layout, options)
+ else
+ render_for_file(name.sub(/^\//, ''), [layout, true], options)
+ end
+ end
+
+ def render_for_parts(parts, layout, options = {})
+ tmp = view_paths.find_by_parts(*parts)
+
+ layout = _pick_layout(*layout) unless tmp.exempt_from_layout?
+
+ render_for_text(
+ @template._render_template_with_layout(tmp, layout, options, parts[3]))
+ end
+
+ def render_for_file(file, layout, options)
+ render_for_parts([file, [request.format.to_sym]], layout, options)
+ end
+
+ def render_for_action(name, layout, options)
+ parts = [action_name_base(name), formats, controller_name]
+ render_for_parts(parts, layout, options)
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/base/request_forgery_protection.rb
index f3e6288c26..f3e6288c26 100644
--- a/actionpack/lib/action_controller/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/base/request_forgery_protection.rb
diff --git a/actionpack/lib/action_controller/base/responder.rb b/actionpack/lib/action_controller/base/responder.rb
new file mode 100644
index 0000000000..989f82444b
--- /dev/null
+++ b/actionpack/lib/action_controller/base/responder.rb
@@ -0,0 +1,42 @@
+module ActionController
+ module Responder
+ def self.included(klass)
+ klass.extend ClassMethods
+ end
+
+ private
+ def render_for_text(text = nil, append_response = false) #:nodoc:
+ @performed_render = true
+
+ if append_response
+ response.body ||= ''
+ response.body << text.to_s
+ else
+ response.body = case text
+ when Proc then text
+ when nil then " " # Safari doesn't pass the headers of the return if the response is zero length
+ else text.to_s
+ end
+ end
+ end
+
+ # Returns a set of the methods defined as actions in your controller
+ def action_methods
+ self.class.action_methods
+ end
+
+ module ClassMethods
+ def action_methods
+ @action_methods ||=
+ # All public instance methods of this class, including ancestors
+ public_instance_methods(true).map { |m| m.to_s }.to_set -
+ # Except for public instance methods of Base and its ancestors
+ Base.public_instance_methods(true).map { |m| m.to_s } +
+ # Be sure to include shadowed public instance methods of this class
+ public_instance_methods(false).map { |m| m.to_s } -
+ # And always exclude explicitly hidden actions
+ hidden_actions
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/streaming.rb b/actionpack/lib/action_controller/base/streaming.rb
index 9f80f48c3d..9f80f48c3d 100644
--- a/actionpack/lib/action_controller/streaming.rb
+++ b/actionpack/lib/action_controller/base/streaming.rb
diff --git a/actionpack/lib/action_controller/verification.rb b/actionpack/lib/action_controller/base/verification.rb
index c62b81b666..c62b81b666 100644
--- a/actionpack/lib/action_controller/verification.rb
+++ b/actionpack/lib/action_controller/base/verification.rb
diff --git a/actionpack/lib/action_controller/cgi_ext.rb b/actionpack/lib/action_controller/cgi/ext.rb
index 406b6f06d6..558748f4bd 100644
--- a/actionpack/lib/action_controller/cgi_ext.rb
+++ b/actionpack/lib/action_controller/cgi/ext.rb
@@ -1,6 +1,6 @@
-require 'action_controller/cgi_ext/stdinput'
-require 'action_controller/cgi_ext/query_extension'
-require 'action_controller/cgi_ext/cookie'
+require 'action_controller/cgi/ext/stdinput'
+require 'action_controller/cgi/ext/query_extension'
+require 'action_controller/cgi/ext/cookie'
class CGI #:nodoc:
include ActionController::CgiExt::Stdinput
diff --git a/actionpack/lib/action_controller/cgi_ext/cookie.rb b/actionpack/lib/action_controller/cgi/ext/cookie.rb
index 9cd19bb12d..9cd19bb12d 100644
--- a/actionpack/lib/action_controller/cgi_ext/cookie.rb
+++ b/actionpack/lib/action_controller/cgi/ext/cookie.rb
diff --git a/actionpack/lib/action_controller/cgi_ext/query_extension.rb b/actionpack/lib/action_controller/cgi/ext/query_extension.rb
index 9620fd2873..9620fd2873 100644
--- a/actionpack/lib/action_controller/cgi_ext/query_extension.rb
+++ b/actionpack/lib/action_controller/cgi/ext/query_extension.rb
diff --git a/actionpack/lib/action_controller/cgi_ext/stdinput.rb b/actionpack/lib/action_controller/cgi/ext/stdinput.rb
index 5e9b6784af..5e9b6784af 100644
--- a/actionpack/lib/action_controller/cgi_ext/stdinput.rb
+++ b/actionpack/lib/action_controller/cgi/ext/stdinput.rb
diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi/process.rb
index 54ff04cfd2..34b97776f5 100644
--- a/actionpack/lib/action_controller/cgi_process.rb
+++ b/actionpack/lib/action_controller/cgi/process.rb
@@ -1,5 +1,3 @@
-require 'action_controller/cgi_ext'
-
module ActionController #:nodoc:
class CGIHandler
module ProperStream
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb
index 07931e4a4a..74c72e1a8b 100644
--- a/actionpack/lib/action_controller/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb
@@ -6,7 +6,7 @@ module ActionController
def define_dispatcher_callbacks(cache_classes)
unless cache_classes
unless self.middleware.include?(Reloader)
- self.middleware.insert_after(Failsafe, Reloader)
+ self.middleware.insert_after(ActionDispatch::Failsafe, Reloader)
end
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
@@ -68,7 +68,7 @@ module ActionController
end
cattr_accessor :middleware
- self.middleware = MiddlewareStack.new do |middleware|
+ self.middleware = ActionDispatch::MiddlewareStack.new do |middleware|
middlewares = File.join(File.dirname(__FILE__), "middlewares.rb")
middleware.instance_eval(File.read(middlewares))
end
diff --git a/actionpack/lib/action_controller/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb
index 371cf6d8f7..b62b4f84a1 100644
--- a/actionpack/lib/action_controller/middlewares.rb
+++ b/actionpack/lib/action_controller/dispatch/middlewares.rb
@@ -2,12 +2,12 @@ use "Rack::Lock", :if => lambda {
!ActionController::Base.allow_concurrency
}
-use "ActionController::Failsafe"
+use "ActionDispatch::Failsafe"
use lambda { ActionController::Base.session_store },
lambda { ActionController::Base.session_options }
-use "ActionController::RewindableInput"
-use "ActionController::ParamsParser"
+use "ActionDispatch::RewindableInput"
+use "ActionDispatch::ParamsParser"
use "Rack::MethodOverride"
use "Rack::Head"
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/dispatch/rescue.rb
index 242c8da920..ec9eff65a9 100644
--- a/actionpack/lib/action_controller/rescue.rb
+++ b/actionpack/lib/action_controller/dispatch/rescue.rb
@@ -38,7 +38,7 @@ module ActionController #:nodoc:
'ActionView::TemplateError' => 'template_error'
}
- RESCUES_TEMPLATE_PATH = ActionView::Template::EagerPath.new_and_loaded(
+ RESCUES_TEMPLATE_PATH = ActionView::Template::EagerPath.new(
File.join(File.dirname(__FILE__), "templates"))
def self.included(base) #:nodoc:
@@ -60,8 +60,8 @@ module ActionController #:nodoc:
module ClassMethods
def call_with_exception(env, exception) #:nodoc:
- request = env["action_controller.rescue.request"] ||= Request.new(env)
- response = env["action_controller.rescue.response"] ||= Response.new
+ request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env)
+ response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new
new.process(request, response, :rescue_action, exception)
end
end
@@ -131,11 +131,13 @@ module ActionController #:nodoc:
@template.instance_variable_set("@exception", exception)
@template.instance_variable_set("@rescues_path", RESCUES_TEMPLATE_PATH)
@template.instance_variable_set("@contents",
- @template.render(:file => template_path_for_local_rescue(exception)))
+ @template._render_template(template_path_for_local_rescue(exception)))
response.content_type = Mime::HTML
- render_for_file(rescues_path("layout"),
- response_code_for_rescue(exception))
+ response.status = interpret_status(response_code_for_rescue(exception))
+
+ content = @template._render_template(rescues_path("layout"))
+ render_for_text(content)
end
def rescue_action_without_handler(exception)
@@ -163,7 +165,7 @@ module ActionController #:nodoc:
end
def rescues_path(template_name)
- RESCUES_TEMPLATE_PATH["rescues/#{template_name}.erb"]
+ RESCUES_TEMPLATE_PATH.find_template("rescues/#{template_name}.erb")
end
def template_path_for_local_rescue(exception)
diff --git a/actionpack/lib/action_controller/templates/rescues/_request_and_response.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb
index 64b34650b1..64b34650b1 100644
--- a/actionpack/lib/action_controller/templates/rescues/_request_and_response.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/_request_and_response.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/_trace.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb
index bb2d8375bd..bb2d8375bd 100644
--- a/actionpack/lib/action_controller/templates/rescues/_trace.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/_trace.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb
index 669da1b26e..95be64511d 100644
--- a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/diagnostics.erb
@@ -6,6 +6,5 @@
</h1>
<pre><%=h @exception.clean_message %></pre>
-<%= render :file => @rescues_path["rescues/_trace.erb"] %>
-
-<%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
+<%= @template._render_template(@rescues_path.find_template("rescues/_trace.erb")) %>
+<%= @template._render_template(@rescues_path.find_template("rescues/_request_and_response.erb")) %> \ No newline at end of file
diff --git a/actionpack/lib/action_controller/templates/rescues/layout.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb
index 4a04742e40..4a04742e40 100644
--- a/actionpack/lib/action_controller/templates/rescues/layout.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/layout.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/missing_template.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb
index dbfdf76947..dbfdf76947 100644
--- a/actionpack/lib/action_controller/templates/rescues/missing_template.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/missing_template.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/routing_error.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb
index ccfa858cce..ccfa858cce 100644
--- a/actionpack/lib/action_controller/templates/rescues/routing_error.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/routing_error.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/template_error.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb
index 2e34e03bd5..2e34e03bd5 100644
--- a/actionpack/lib/action_controller/templates/rescues/template_error.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/template_error.erb
diff --git a/actionpack/lib/action_controller/templates/rescues/unknown_action.erb b/actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb
index 683379da10..683379da10 100644
--- a/actionpack/lib/action_controller/templates/rescues/unknown_action.erb
+++ b/actionpack/lib/action_controller/dispatch/templates/rescues/unknown_action.erb
diff --git a/actionpack/lib/action_controller/mime_responds.rb b/actionpack/lib/action_controller/mime/responds.rb
index b755363873..bac225ab2a 100644
--- a/actionpack/lib/action_controller/mime_responds.rb
+++ b/actionpack/lib/action_controller/mime/responds.rb
@@ -109,16 +109,13 @@ module ActionController #:nodoc:
end
class Responder #:nodoc:
+
def initialize(controller)
@controller = controller
@request = controller.request
@response = controller.response
- if ActionController::Base.use_accept_header
- @mime_type_priority = Array(Mime::Type.lookup_by_extension(@request.parameters[:format]) || @request.accepts)
- else
- @mime_type_priority = [@request.format]
- end
+ @mime_type_priority = @request.formats
@order = []
@responses = {}
@@ -130,7 +127,7 @@ module ActionController #:nodoc:
@order << mime_type
@responses[mime_type] ||= Proc.new do
- @response.template.template_format = mime_type.to_sym
+ @response.template.formats = [mime_type.to_sym]
@response.content_type = mime_type.to_s
block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
end
diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb
new file mode 100644
index 0000000000..7c65f1cdc1
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base.rb
@@ -0,0 +1,7 @@
+module ActionController
+ autoload :AbstractBase, "action_controller/new_base/base"
+ autoload :HideActions, "action_controller/new_base/hide_actions"
+ autoload :Layouts, "action_controller/new_base/layouts"
+ autoload :Renderer, "action_controller/new_base/renderer"
+ autoload :UrlFor, "action_controller/new_base/url_for"
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb
new file mode 100644
index 0000000000..0400ddbf7a
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/base.rb
@@ -0,0 +1,61 @@
+module ActionController
+ class AbstractBase < AbstractController::Base
+
+ # :api: public
+ attr_internal :request, :response, :params
+
+ # :api: public
+ def self.controller_name
+ @controller_name ||= controller_path.split("/").last
+ end
+
+ # :api: public
+ def controller_name() self.class.controller_name end
+
+ # :api: public
+ def self.controller_path
+ @controller_path ||= self.name.sub(/Controller$/, '').underscore
+ end
+
+ # :api: public
+ def controller_path() self.class.controller_path end
+
+ # :api: private
+ def self.action_methods
+ @action_names ||= Set.new(self.public_instance_methods - self::CORE_METHODS)
+ end
+
+ # :api: private
+ def self.action_names() action_methods end
+
+ # :api: private
+ def action_methods() self.class.action_names end
+
+ # :api: private
+ def action_names() action_methods end
+
+ # :api: plugin
+ def self.call(env)
+ controller = new
+ controller.call(env).to_rack
+ end
+
+ # :api: plugin
+ def response_body=(body)
+ @_response["Content-Length"] = body.length
+ @_response.body = body
+ end
+
+ # :api: private
+ def call(env)
+ @_request = ActionDispatch::Request.new(env)
+ @_response = ActionDispatch::Response.new
+ process(@_request.parameters[:action])
+ end
+
+ # :api: private
+ def to_rack
+ response.to_a
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb
new file mode 100644
index 0000000000..473a8ea72b
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/hide_actions.rb
@@ -0,0 +1,31 @@
+module ActionController
+ module HideActions
+ setup do
+ extlib_inheritable_accessor :hidden_actions
+ self.hidden_actions ||= Set.new
+ end
+
+ def action_methods() self.class.action_names end
+ def action_names() action_methods end
+
+ private
+
+ def respond_to_action?(action_name)
+ !hidden_actions.include?(action_name) && (super || respond_to?(:method_missing))
+ end
+
+ module ClassMethods
+ def hide_action(*args)
+ args.each do |arg|
+ self.hidden_actions << arg.to_s
+ end
+ end
+
+ def action_methods
+ @action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)})
+ end
+
+ def self.action_names() action_methods end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb
new file mode 100644
index 0000000000..149847c968
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/layouts.rb
@@ -0,0 +1,37 @@
+module ActionController
+ module Layouts
+ depends_on ActionController::Renderer
+ depends_on AbstractController::Layouts
+
+ module ClassMethods
+ def _implied_layout_name
+ controller_path
+ end
+ end
+
+ def render_to_string(options)
+ # render :text => ..., :layout => ...
+ # or
+ # render :anything_else
+ if !options.key?(:text) || options.key?(:layout)
+ options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout
+ end
+
+ super
+ end
+
+ private
+
+ def _layout_for_option(name)
+ case name
+ when String then _layout_for_name(name)
+ when true then _default_layout(true)
+ when false, nil then nil
+ else
+ raise ArgumentError,
+ "String, true, or false, expected for `layout'; you passed #{name.inspect}"
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb
new file mode 100644
index 0000000000..044c15f409
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/renderer.rb
@@ -0,0 +1,62 @@
+module ActionController
+ module Renderer
+ depends_on AbstractController::Renderer
+
+ def initialize(*)
+ self.formats = [:html]
+ super
+ end
+
+ def render(action, options = {})
+ # TODO: Move this into #render_to_string
+ if action.is_a?(Hash)
+ options, action = action, nil
+ else
+ options.merge! :action => action
+ end
+
+ _process_options(options)
+
+ self.response_body = render_to_string(options)
+ end
+
+ def render_to_string(options)
+ unless options.is_a?(Hash)
+ options = {:action => options}
+ end
+
+ if options.key?(:text)
+ options[:_template] = ActionView::TextTemplate.new(_text(options))
+ template = nil
+ elsif options.key?(:template)
+ options[:_template_name] = options[:template]
+ elsif options.key?(:action)
+ options[:_template_name] = options[:action].to_s
+ options[:_prefix] = _prefix
+ end
+
+ super(options)
+ end
+
+ private
+
+ def _prefix
+ controller_path
+ end
+
+ def _text(options)
+ text = options[:text]
+
+ case text
+ when nil then " "
+ else text.to_s
+ end
+ end
+
+ def _process_options(options)
+ if status = options[:status]
+ response.status = status.to_i
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb
new file mode 100644
index 0000000000..af5b21012b
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/url_for.rb
@@ -0,0 +1,40 @@
+module ActionController
+ module UrlFor
+ def initialize_current_url
+ @url = UrlRewriter.new(request, params.clone)
+ end
+
+ # Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
+ # the form of a hash, just like the one you would use for url_for directly. Example:
+ #
+ # def default_url_options(options)
+ # { :project => @project.active? ? @project.url_name : "unknown" }
+ # end
+ #
+ # As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the
+ # urls as they stem from the business domain. Please note that any individual url_for call can always override the defaults set
+ # by this method.
+ def default_url_options(options = nil)
+ end
+
+ def rewrite_options(options) #:nodoc:
+ if defaults = default_url_options(options)
+ defaults.merge(options)
+ else
+ options
+ end
+ end
+
+ def url_for(options = {})
+ options ||= {}
+ case options
+ when String
+ options
+ when Hash
+ @url.rewrite(rewrite_options(options))
+ else
+ polymorphic_url(options)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index 742d290ad6..6bda27e23a 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionController
# The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
# Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate
# the view actions to a higher logical level. Example:
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
index d9b614c237..d9b614c237 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/routing/generation/polymorphic_routes.rb
diff --git a/actionpack/lib/action_controller/url_rewriter.rb b/actionpack/lib/action_controller/routing/generation/url_rewriter.rb
index 16720b915b..16720b915b 100644
--- a/actionpack/lib/action_controller/url_rewriter.rb
+++ b/actionpack/lib/action_controller/routing/generation/url_rewriter.rb
diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/routing/resources.rb
index 86abb7b2f4..86abb7b2f4 100644
--- a/actionpack/lib/action_controller/resources.rb
+++ b/actionpack/lib/action_controller/routing/resources.rb
diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb
index 044ace7de1..70cd1f642d 100644
--- a/actionpack/lib/action_controller/routing/route_set.rb
+++ b/actionpack/lib/action_controller/routing/route_set.rb
@@ -428,7 +428,7 @@ module ActionController
end
def call(env)
- request = Request.new(env)
+ request = ActionDispatch::Request.new(env)
app = Routing::Routes.recognize(request)
app.call(env).to_a
end
diff --git a/actionpack/lib/action_controller/session_management.rb b/actionpack/lib/action_controller/session/management.rb
index b556f04649..ffce8e1bd1 100644
--- a/actionpack/lib/action_controller/session_management.rb
+++ b/actionpack/lib/action_controller/session/management.rb
@@ -26,7 +26,7 @@ module ActionController #:nodoc:
if defined? @@session_store
@@session_store
else
- Session::CookieStore
+ ActionDispatch::Session::CookieStore
end
end
diff --git a/actionpack/lib/action_controller/assertions/dom_assertions.rb b/actionpack/lib/action_controller/testing/assertions/dom.rb
index 5ffe5f1883..5ffe5f1883 100644
--- a/actionpack/lib/action_controller/assertions/dom_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/dom.rb
diff --git a/actionpack/lib/action_controller/assertions/model_assertions.rb b/actionpack/lib/action_controller/testing/assertions/model.rb
index 3a7b39b106..3a7b39b106 100644
--- a/actionpack/lib/action_controller/assertions/model_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/model.rb
diff --git a/actionpack/lib/action_controller/assertions/response_assertions.rb b/actionpack/lib/action_controller/testing/assertions/response.rb
index 5976090273..ca0a9bbf52 100644
--- a/actionpack/lib/action_controller/assertions/response_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/response.rb
@@ -11,7 +11,7 @@ module ActionController
#
# You can also pass an explicit status number like assert_response(501)
# or its symbolic equivalent assert_response(:not_implemented).
- # See ActionController::StatusCodes for a full list.
+ # See ActionDispatch::StatusCodes for a full list.
#
# ==== Examples
#
@@ -27,7 +27,7 @@ module ActionController
assert_block("") { true } # to count the assertion
elsif type.is_a?(Fixnum) && @response.response_code == type
assert_block("") { true } # to count the assertion
- elsif type.is_a?(Symbol) && @response.response_code == ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
+ elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
assert_block("") { true } # to count the assertion
else
if @response.error?
diff --git a/actionpack/lib/action_controller/assertions/routing_assertions.rb b/actionpack/lib/action_controller/testing/assertions/routing.rb
index 5101751cea..5101751cea 100644
--- a/actionpack/lib/action_controller/assertions/routing_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/routing.rb
diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/testing/assertions/selector.rb
index 0d56ea5ef7..0d56ea5ef7 100644
--- a/actionpack/lib/action_controller/assertions/selector_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/selector.rb
diff --git a/actionpack/lib/action_controller/assertions/tag_assertions.rb b/actionpack/lib/action_controller/testing/assertions/tag.rb
index 80249e0e83..80249e0e83 100644
--- a/actionpack/lib/action_controller/assertions/tag_assertions.rb
+++ b/actionpack/lib/action_controller/testing/assertions/tag.rb
diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/testing/integration.rb
index fda6b639d1..d51b9b63ff 100644
--- a/actionpack/lib/action_controller/integration.rb
+++ b/actionpack/lib/action_controller/testing/integration.rb
@@ -323,7 +323,7 @@ module ActionController
@html_document = nil
@status = status.to_i
- @status_message = StatusCodes::STATUS_CODES[@status]
+ @status_message = ActionDispatch::StatusCodes::STATUS_CODES[@status]
@headers = Rack::Utils::HeaderHash.new(headers)
@@ -348,7 +348,7 @@ module ActionController
else
# Decorate responses from Rack Middleware and Rails Metal
# as an Response for the purposes of integration testing
- @response = Response.new
+ @response = ActionDispatch::Response.new
@response.status = status.to_s
@response.headers.replace(@headers)
@response.body = @body_parts
@@ -387,7 +387,7 @@ module ActionController
"SERVER_PORT" => https? ? "443" : "80",
"HTTPS" => https? ? "on" : "off"
}
- UrlRewriter.new(Request.new(env), {})
+ UrlRewriter.new(ActionDispatch::Request.new(env), {})
end
def name_with_prefix(prefix, name)
diff --git a/actionpack/lib/action_controller/performance_test.rb b/actionpack/lib/action_controller/testing/performance.rb
index d88180087d..d88180087d 100644
--- a/actionpack/lib/action_controller/performance_test.rb
+++ b/actionpack/lib/action_controller/testing/performance.rb
diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/testing/process.rb
index fbc1b519bf..86e193efa9 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/testing/process.rb
@@ -1,6 +1,6 @@
require 'rack/session/abstract/id'
module ActionController #:nodoc:
- class TestRequest < Request #:nodoc:
+ class TestRequest < ActionDispatch::Request #:nodoc:
attr_accessor :cookies, :session_options
attr_accessor :query_parameters, :path, :session
attr_accessor :host
@@ -283,7 +283,7 @@ module ActionController #:nodoc:
# controller actions.
#
# See Response for more information on controller response objects.
- class TestResponse < Response
+ class TestResponse < ActionDispatch::Response
include TestResponseBehavior
def recycle!
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/testing/test_case.rb
index d2059d51f4..b020b755a0 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/testing/test_case.rb
@@ -1,5 +1,5 @@
require 'active_support/test_case'
-require 'action_controller/test_process'
+require 'action_controller/testing/process'
module ActionController
# Superclass for ActionController functional tests. Functional tests allow you to
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
new file mode 100644
index 0000000000..393ccaa795
--- /dev/null
+++ b/actionpack/lib/action_dispatch.rb
@@ -0,0 +1,64 @@
+#--
+# Copyright (c) 2004-2009 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#++
+
+begin
+ require 'active_support'
+rescue LoadError
+ activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
+ if File.directory?(activesupport_path)
+ $:.unshift activesupport_path
+ require 'active_support'
+ end
+end
+
+gem 'rack', '>= 0.9.0'
+require 'rack'
+require 'action_dispatch/rack'
+
+module ActionDispatch
+ autoload :Request, 'action_dispatch/http/request'
+ autoload :Response, 'action_dispatch/http/response'
+ autoload :StatusCodes, 'action_dispatch/http/status_codes'
+
+ autoload :Failsafe, 'action_dispatch/middleware/failsafe'
+ autoload :ParamsParser, 'action_dispatch/middleware/params_parser'
+ autoload :RewindableInput, 'action_dispatch/middleware/rewindable_input'
+
+ autoload :MiddlewareStack, 'action_dispatch/utils/middleware_stack'
+ autoload :UploadedFile, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedStringIO, 'action_dispatch/utils/uploaded_file'
+ autoload :UploadedTempfile, 'action_dispatch/utils/uploaded_file'
+ autoload :UrlEncodedPairParser, 'action_dispatch/utils/url_encoded_pair_parser'
+
+ module Http
+ autoload :Headers, 'action_dispatch/http/headers'
+ end
+
+ module Session
+ autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
+ autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
+ autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
+ end
+end
+
+autoload :Mime, 'action_dispatch/http/mime_type'
diff --git a/actionpack/lib/action_controller/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb
index 139669c66f..2a41b4dbad 100644
--- a/actionpack/lib/action_controller/headers.rb
+++ b/actionpack/lib/action_dispatch/http/headers.rb
@@ -1,6 +1,6 @@
require 'active_support/memoizable'
-module ActionController
+module ActionDispatch
module Http
class Headers < ::Hash
extend ActiveSupport::Memoizable
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 017626ba27..02ad7f7d94 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -5,6 +5,10 @@ module Mime
EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
+ def self.[](type)
+ Type.lookup_by_extension(type.to_s)
+ end
+
# Encapsulates the notion of a mime type. Can be used at render time, for example, with:
#
# class PostsController < ActionController::Base
@@ -27,7 +31,7 @@ module Mime
# only needs to protect against these types.
@@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form, :text]
cattr_reader :browser_generated_types
-
+ attr_reader :symbol
@@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
def self.unverifiable_types
@@ -187,17 +191,13 @@ module Mime
# Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See
# ActionController::RequestForgeryProtection.
def verify_request?
- browser_generated?
+ @@browser_generated_types.include?(to_sym)
end
def html?
@@html_types.include?(to_sym) || @string =~ /html/
end
- def browser_generated?
- @@browser_generated_types.include?(to_sym)
- end
-
private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
@@ -209,4 +209,4 @@ module Mime
end
end
-require 'action_controller/mime_types'
+require 'action_dispatch/http/mime_types'
diff --git a/actionpack/lib/action_controller/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb
index 2d7fba1173..2d7fba1173 100644
--- a/actionpack/lib/action_controller/mime_types.rb
+++ b/actionpack/lib/action_dispatch/http/mime_types.rb
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index ef223f157c..7d47a1566e 100755
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -3,9 +3,8 @@ require 'stringio'
require 'strscan'
require 'active_support/memoizable'
-require 'action_controller/cgi_ext'
-module ActionController
+module ActionDispatch
class Request < Rack::Request
%w[ AUTH_TYPE GATEWAY_INTERFACE
@@ -32,7 +31,7 @@ module ActionController
# <tt>:get</tt>. If the request \method is not listed in the HTTP_METHODS
# constant above, an UnknownHttpMethod exception is raised.
def request_method
- @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
+ @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(ActionController::UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
end
# Returns the HTTP request \method used for action processing as a
@@ -73,7 +72,7 @@ module ActionController
#
# request.headers["Content-Type"] # => "text/plain"
def headers
- @headers ||= ActionController::Http::Headers.new(@env)
+ Http::Headers.new(@env)
end
# Returns the content length of the request as an integer.
@@ -94,20 +93,26 @@ module ActionController
end
end
end
-
+
# Returns the accepted MIME type for the request.
def accepts
@accepts ||= begin
header = @env['HTTP_ACCEPT'].to_s.strip
+ fallback = xhr? ? Mime::JS : Mime::HTML
+
if header.empty?
- [content_type, Mime::ALL].compact
+ [content_type, fallback, Mime::ALL].compact
else
- Mime::Type.parse(header)
+ ret = Mime::Type.parse(header)
+ if ret.last == Mime::ALL
+ ret.insert(-2, fallback)
+ end
+ ret
end
end
end
-
+
def if_modified_since
if since = env['HTTP_IF_MODIFIED_SINCE']
Time.rfc2822(since) rescue nil
@@ -142,24 +147,33 @@ module ActionController
end
end
+ ONLY_ALL = [Mime::ALL].freeze
+
# Returns the Mime type for the \format used in the request.
#
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
- def format
+
+ def format(view_path = [])
@format ||=
if parameters[:format]
- Mime::Type.lookup_by_extension(parameters[:format])
- elsif ActionController::Base.use_accept_header
- accepts.first
- elsif xhr?
- Mime::Type.lookup_by_extension("js")
- else
- Mime::Type.lookup_by_extension("html")
+ Mime[parameters[:format]]
+ elsif ActionController::Base.use_accept_header && !(accepts == ONLY_ALL)
+ accepts.first
+ elsif xhr? then Mime::JS
+ else Mime::HTML
end
end
+ def formats
+ @formats =
+ if ActionController::Base.use_accept_header
+ Array(Mime[parameters[:format]] || accepts)
+ else
+ [format]
+ end
+ end
# Sets the \format by string extension, which can be used to force custom formats
# that are not controlled by the extension.
@@ -226,7 +240,7 @@ module ActionController
if @env.include? 'HTTP_CLIENT_IP'
if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
# We don't know which came from the proxy, and which from the user
- raise ActionControllerError.new(<<EOM)
+ raise ActionController::ActionControllerError.new(<<EOM)
IP spoofing attack?!
HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index febe4ccf29..ecf40b8103 100644
--- a/actionpack/lib/action_controller/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -1,6 +1,6 @@
require 'digest/md5'
-module ActionController # :nodoc:
+module ActionDispatch # :nodoc:
# Represents an HTTP response generated by a controller action. One can use
# an ActionController::Response object to retrieve the current state
# of the response, or customize the response. An Response object can
diff --git a/actionpack/lib/action_controller/status_codes.rb b/actionpack/lib/action_dispatch/http/status_codes.rb
index 4977c79491..cec9d2e3a1 100644
--- a/actionpack/lib/action_controller/status_codes.rb
+++ b/actionpack/lib/action_dispatch/http/status_codes.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
module StatusCodes #:nodoc:
# Defines the standard HTTP status codes, by integer, with their
# corresponding default message texts.
diff --git a/actionpack/lib/action_controller/failsafe.rb b/actionpack/lib/action_dispatch/middleware/failsafe.rb
index 567581142c..7379a696aa 100644
--- a/actionpack/lib/action_controller/failsafe.rb
+++ b/actionpack/lib/action_dispatch/middleware/failsafe.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
class Failsafe
cattr_accessor :error_file_path
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
diff --git a/actionpack/lib/action_controller/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index d269fe07fa..6df572268c 100644
--- a/actionpack/lib/action_controller/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
class ParamsParser
ActionController::Base.param_parsers[Mime::XML] = :xml_simple
ActionController::Base.param_parsers[Mime::JSON] = :json
diff --git a/actionpack/lib/action_controller/rewindable_input.rb b/actionpack/lib/action_dispatch/middleware/rewindable_input.rb
index cedfb7fd75..725414efc4 100644
--- a/actionpack/lib/action_controller/rewindable_input.rb
+++ b/actionpack/lib/action_dispatch/middleware/rewindable_input.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
class RewindableInput
class RewindableIO < ActiveSupport::BasicObject
def initialize(io)
diff --git a/actionpack/lib/action_controller/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index f6369abf15..6c039cf62d 100644
--- a/actionpack/lib/action_controller/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -1,6 +1,6 @@
require 'rack/utils'
-module ActionController
+module ActionDispatch
module Session
class AbstractStore
ENV_SESSION_KEY = 'rack.session'.freeze
diff --git a/actionpack/lib/action_controller/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index a2543c1824..433c4cc070 100644
--- a/actionpack/lib/action_controller/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
module Session
# This cookie-based session store is the Rails default. Sessions typically
# contain at most a user_id and flash message; both fit within the 4K cookie
diff --git a/actionpack/lib/action_controller/session/mem_cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
index f745715a97..8f448970d9 100644
--- a/actionpack/lib/action_controller/session/mem_cache_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb
@@ -1,7 +1,7 @@
begin
require_library_or_gem 'memcache'
- module ActionController
+ module ActionDispatch
module Session
class MemCacheStore < AbstractStore
def initialize(app, options = {})
diff --git a/actionpack/lib/action_dispatch/rack.rb b/actionpack/lib/action_dispatch/rack.rb
new file mode 100644
index 0000000000..89087c124f
--- /dev/null
+++ b/actionpack/lib/action_dispatch/rack.rb
@@ -0,0 +1,3 @@
+# require 'action_dispatch/rack/lock'
+# require 'action_dispatch/rack/multipart'
+# require 'action_dispatch/rack/parse_query'
diff --git a/actionpack/lib/action_controller/middleware_stack.rb b/actionpack/lib/action_dispatch/utils/middleware_stack.rb
index b739a6d72d..ee5f28d5cb 100644
--- a/actionpack/lib/action_controller/middleware_stack.rb
+++ b/actionpack/lib/action_dispatch/utils/middleware_stack.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
class MiddlewareStack < Array
class Middleware
def self.new(klass, *args, &block)
diff --git a/actionpack/lib/action_controller/uploaded_file.rb b/actionpack/lib/action_dispatch/utils/uploaded_file.rb
index 376ba3621a..97dffa089f 100644
--- a/actionpack/lib/action_controller/uploaded_file.rb
+++ b/actionpack/lib/action_dispatch/utils/uploaded_file.rb
@@ -1,4 +1,4 @@
-module ActionController
+module ActionDispatch
module UploadedFile
def self.included(base)
base.class_eval do
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 1f1ff9dd05..14bd2a1297 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -31,6 +31,8 @@ rescue LoadError
end
end
+require File.join(File.dirname(__FILE__), "action_pack")
+
module ActionView
def self.load_all!
[Base, InlineTemplate, TemplateError]
@@ -38,16 +40,17 @@ module ActionView
autoload :Base, 'action_view/base'
autoload :Helpers, 'action_view/helpers'
- autoload :InlineTemplate, 'action_view/inline_template'
- autoload :Partials, 'action_view/partials'
+ autoload :InlineTemplate, 'action_view/template/inline'
+ autoload :Partials, 'action_view/render/partials'
autoload :PathSet, 'action_view/paths'
- autoload :Renderable, 'action_view/renderable'
- autoload :RenderablePartial, 'action_view/renderable_partial'
- autoload :Template, 'action_view/template'
- autoload :ReloadableTemplate, 'action_view/reloadable_template'
- autoload :TemplateError, 'action_view/template_error'
- autoload :TemplateHandler, 'action_view/template_handler'
- autoload :TemplateHandlers, 'action_view/template_handlers'
+ autoload :Rendering, 'action_view/render/rendering'
+ autoload :Renderable, 'action_view/template/renderable'
+ autoload :RenderablePartial, 'action_view/template/partial'
+ autoload :Template, 'action_view/template/template'
+ autoload :TemplateError, 'action_view/template/error'
+ autoload :TemplateHandler, 'action_view/template/handler'
+ autoload :TemplateHandlers, 'action_view/template/handlers'
+ autoload :TextTemplate, 'action_view/template/text'
autoload :Helpers, 'action_view/helpers'
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 9c0134e7f7..efed19a21d 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -3,10 +3,11 @@ module ActionView #:nodoc:
end
class MissingTemplate < ActionViewError #:nodoc:
- attr_reader :path
+ attr_reader :path, :action_name
def initialize(paths, path, template_format = nil)
@path = path
+ @action_name = path.split("/").last.split(".")[0...-1].join(".")
full_template_path = path.include?('.') ? path : "#{path}.erb"
display_paths = paths.compact.join(":")
template_type = (path =~ /layouts/i) ? 'layout' : 'template'
@@ -160,14 +161,13 @@ module ActionView #:nodoc:
#
# See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
class Base
- include Helpers, Partials, ::ERB::Util
+ include Helpers, Rendering, Partials, ::ERB::Util
+
extend ActiveSupport::Memoizable
- attr_accessor :base_path, :assigns, :template_extension
+ attr_accessor :base_path, :assigns, :template_extension, :formats
attr_accessor :controller
- attr_writer :template_format
-
attr_accessor :output_buffer
class << self
@@ -193,9 +193,13 @@ module ActionView #:nodoc:
attr_internal :request
+ delegate :controller_path, :to => :controller, :allow_nil => true
+
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
:flash, :logger, :action_name, :controller_name, :to => :controller
+ delegate :find_by_parts, :to => :view_paths
+
module CompiledTemplates #:nodoc:
# holds compiled template code
end
@@ -218,7 +222,8 @@ module ActionView #:nodoc:
end
end
- def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
+ def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc:
+ @formats = formats || [:html]
@assigns = assigns_for_first_render
@assigns_added = nil
@controller = controller
@@ -233,56 +238,6 @@ module ActionView #:nodoc:
def view_paths=(paths)
@view_paths = self.class.process_view_paths(paths)
- # we might be using ReloadableTemplates, so we need to let them know this a new request
- @view_paths.load!
- end
-
- # Returns the result of a render that's dictated by the options hash. The primary options are:
- #
- # * <tt>:partial</tt> - See ActionView::Partials.
- # * <tt>:update</tt> - Calls update_page with the block given.
- # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
- # * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
- # * <tt>:text</tt> - Renders the text passed in out.
- #
- # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
- # as the locals hash.
- def render(options = {}, local_assigns = {}, &block) #:nodoc:
- local_assigns ||= {}
-
- case options
- when Hash
- options = options.reverse_merge(:locals => {})
- if options[:layout]
- _render_with_layout(options, local_assigns, &block)
- elsif options[:file]
- template = self.view_paths.find_template(options[:file], template_format)
- template.render_template(self, options[:locals])
- elsif options[:partial]
- render_partial(options)
- elsif options[:inline]
- InlineTemplate.new(options[:inline], options[:type]).render(self, options[:locals])
- elsif options[:text]
- options[:text]
- end
- when :update
- update_page(&block)
- else
- render_partial(:partial => options, :locals => local_assigns)
- end
- end
-
- # The format to be used when choosing between multiple templates with
- # the same name but differing formats. See +Request#template_format+
- # for more details.
- def template_format
- if defined? @template_format
- @template_format
- elsif controller && controller.respond_to?(:request)
- @template_format = controller.request.template_format.to_sym
- else
- @template_format = :html
- end
end
# Access the current template being rendered.
@@ -332,32 +287,5 @@ module ActionView #:nodoc:
controller.response.content_type ||= content_type
end
end
-
- def _render_with_layout(options, local_assigns, &block) #:nodoc:
- partial_layout = options.delete(:layout)
-
- if block_given?
- begin
- @_proc_for_layout = block
- concat(render(options.merge(:partial => partial_layout)))
- ensure
- @_proc_for_layout = nil
- end
- else
- begin
- original_content_for_layout = @content_for_layout if defined?(@content_for_layout)
- @content_for_layout = render(options)
-
- if (options[:inline] || options[:file] || options[:text])
- @cached_content_for_layout = @content_for_layout
- render(:file => partial_layout, :locals => local_assigns)
- else
- render(options.merge(:partial => partial_layout))
- end
- ensure
- @content_for_layout = original_content_for_layout
- end
- end
- end
end
end
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 91ef72e54b..6bad11e354 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -987,13 +987,13 @@ module ActionView
end
def render(*options_for_render)
- old_format = @context && @context.template_format
- @context.template_format = :html if @context
+ old_formats = @context && @context.formats
+ @context.formats = [:html] if @context
Hash === options_for_render.first ?
@context.render(*options_for_render) :
options_for_render.first.to_s
ensure
- @context.template_format = old_format if @context
+ @context.formats = old_formats if @context
end
def javascript_object_for(object)
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index a0a2f96886..b6bb9942ee 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -2,16 +2,16 @@ module ActionView #:nodoc:
class PathSet < Array #:nodoc:
def self.type_cast(obj)
if obj.is_a?(String)
- if Base.cache_template_loading?
- Template::EagerPath.new(obj.to_s)
+ if !Object.const_defined?(:Rails) || Rails.configuration.cache_classes
+ Template::EagerPath.new(obj)
else
- ReloadableTemplate::ReloadablePath.new(obj.to_s)
+ Template::Path.new(obj)
end
else
obj
end
end
-
+
def initialize(*args)
super(*args).map! { |obj| self.class.type_cast(obj) }
end
@@ -35,9 +35,29 @@ module ActionView #:nodoc:
def unshift(*objs)
super(*objs.map { |obj| self.class.type_cast(obj) })
end
+
+ def find_by_parts(path, extension = nil, prefix = nil, partial = false)
+ template_path = path.sub(/^\//, '')
+
+ each do |load_path|
+ if template = load_path.find_by_parts(template_path, extension, prefix, partial)
+ return template
+ end
+ end
+
+ Template.new(path, self)
+ rescue ActionView::MissingTemplate => e
+ extension ||= []
+ raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}.{#{extension.join(",")}}")
+ end
- def load!
- each(&:load!)
+ def find_by_parts?(path, extension = nil, prefix = nil, partial = false)
+ template_path = path.sub(/^\//, '')
+
+ each do |load_path|
+ return true if template = load_path.find_by_parts(template_path, extension, prefix, partial)
+ end
+ false
end
def find_template(original_template_path, format = nil, html_fallback = true)
@@ -45,13 +65,7 @@ module ActionView #:nodoc:
template_path = original_template_path.sub(/^\//, '')
each do |load_path|
- if format && (template = load_path["#{template_path}.#{I18n.locale}.#{format}"])
- return template
- elsif format && (template = load_path["#{template_path}.#{format}"])
- return template
- elsif template = load_path["#{template_path}.#{I18n.locale}"]
- return template
- elsif template = load_path[template_path]
+ if template = load_path.find_by_parts(template_path, format)
return template
# Try to find html version if the format is javascript
elsif format == :js && html_fallback && template = load_path["#{template_path}.#{I18n.locale}.html"]
@@ -61,7 +75,7 @@ module ActionView #:nodoc:
end
end
- return Template.new(original_template_path) if File.file?(original_template_path)
+ return Template.new(original_template_path, original_template_path.to_s =~ /\A\// ? "" : ".") if File.file?(original_template_path)
raise MissingTemplate.new(self, original_template_path, format)
end
diff --git a/actionpack/lib/action_view/reloadable_template.rb b/actionpack/lib/action_view/reloadable_template.rb
deleted file mode 100644
index 5ef833d75c..0000000000
--- a/actionpack/lib/action_view/reloadable_template.rb
+++ /dev/null
@@ -1,117 +0,0 @@
-module ActionView #:nodoc:
- class ReloadableTemplate < Template
-
- class TemplateDeleted < ActionView::ActionViewError
- end
-
- class ReloadablePath < Template::Path
-
- def initialize(path)
- super
- @paths = {}
- new_request!
- end
-
- def new_request!
- @disk_cache = {}
- end
- alias_method :load!, :new_request!
-
- def [](path)
- if found_template = @paths[path]
- begin
- found_template.reset_cache_if_stale!
- rescue TemplateDeleted
- unregister_template(found_template)
- self[path]
- end
- else
- load_all_templates_from_dir(templates_dir_from_path(path))
- # don't ever hand out a template without running a stale check
- (new_template = @paths[path]) && new_template.reset_cache_if_stale!
- end
- end
-
- private
- def register_template_from_file(template_full_file_path)
- if !@paths[relative_path = relative_path_for_template_file(template_full_file_path)] && File.file?(template_full_file_path)
- register_template(ReloadableTemplate.new(relative_path, self))
- end
- end
-
- def register_template(template)
- template.accessible_paths.each do |path|
- @paths[path] = template
- end
- end
-
- # remove (probably deleted) template from cache
- def unregister_template(template)
- template.accessible_paths.each do |template_path|
- @paths.delete(template_path) if @paths[template_path] == template
- end
- # fill in any newly created gaps
- @paths.values.uniq.each do |template|
- template.accessible_paths.each {|path| @paths[path] ||= template}
- end
- end
-
- # load all templates from the directory of the requested template
- def load_all_templates_from_dir(dir)
- # hit disk only once per template-dir/request
- @disk_cache[dir] ||= template_files_from_dir(dir).each {|template_file| register_template_from_file(template_file)}
- end
-
- def templates_dir_from_path(path)
- dirname = File.dirname(path)
- File.join(@path, dirname == '.' ? '' : dirname)
- end
-
- # get all the template filenames from the dir
- def template_files_from_dir(dir)
- Dir.glob(File.join(dir, '*'))
- end
- end
-
- module Unfreezable
- def freeze; self; end
- end
-
- def initialize(*args)
- super
-
- # we don't ever want to get frozen
- extend Unfreezable
- end
-
- def mtime
- File.mtime(filename)
- end
-
- attr_accessor :previously_last_modified
-
- def stale?
- previously_last_modified.nil? || previously_last_modified < mtime
- rescue Errno::ENOENT => e
- undef_my_compiled_methods!
- raise TemplateDeleted
- end
-
- def reset_cache_if_stale!
- if stale?
- flush_cache 'source', 'compiled_source'
- undef_my_compiled_methods!
- @previously_last_modified = mtime
- end
- self
- end
-
- # remove any compiled methods that look like they might belong to me
- def undef_my_compiled_methods!
- ActionView::Base::CompiledTemplates.public_instance_methods.grep(/#{Regexp.escape(method_name_without_locals)}(?:_locals_)?/).each do |m|
- ActionView::Base::CompiledTemplates.send(:remove_method, m)
- end
- end
-
- end
-end
diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 9e5e0f786e..e337dcb63b 100644
--- a/actionpack/lib/action_view/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -172,68 +172,156 @@ module ActionView
module Partials
extend ActiveSupport::Memoizable
+ def _render_partial(options = {}) #:nodoc:
+ options[:locals] ||= {}
+
+ case path = partial = options[:partial]
+ when *_array_like_objects
+ return _render_partial_collection(partial, options)
+ else
+ if partial.is_a?(ActionView::Helpers::FormBuilder)
+ path = partial.class.to_s.demodulize.underscore.sub(/_builder$/, '')
+ options[:locals].merge!(path.to_sym => partial)
+ elsif !partial.is_a?(String)
+ options[:object] = object = partial
+ path = ActionController::RecordIdentifier.partial_path(object, controller_path)
+ end
+ _, _, prefix, object = parts = partial_parts(path, options)
+ template = find_by_parts(*parts)
+ _render_partial_object(template, options, (object unless object == true))
+ end
+ end
+
private
- def render_partial(options = {}) #:nodoc:
- local_assigns = options[:locals] || {}
+ def partial_parts(name, options)
+ segments = name.split("/")
+ parts = segments.pop.split(".")
- case partial_path = options[:partial]
- when String, Symbol, NilClass
- if options.has_key?(:collection)
- render_partial_collection(options)
- else
- _pick_partial_template(partial_path).render_partial(self, options[:object], local_assigns)
+ case parts.size
+ when 1
+ parts
+ when 2, 3
+ extension = parts.delete_at(1).to_sym
+ if formats.include?(extension)
+ self.formats.replace [extension]
end
- when ActionView::Helpers::FormBuilder
- builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '')
- local_assigns.merge!(builder_partial_path.to_sym => partial_path)
- render_partial(:partial => builder_partial_path, :object => options[:object], :locals => local_assigns)
+ parts.pop if parts.size == 2
+ end
+
+ path = parts.join(".")
+ prefix = segments[0..-1].join("/")
+ prefix = prefix.blank? ? controller_path : prefix
+ parts = [path, formats, prefix]
+ parts.push options[:object] || true
+ end
+
+ def _render_partial_with_block(layout, block, options)
+ @_proc_for_layout = block
+ concat(_render_partial(options.merge(:partial => layout)))
+ ensure
+ @_proc_for_layout = nil
+ end
+
+ def _render_partial_with_layout(layout, options)
+ if layout
+ prefix = controller && !layout.include?("/") ? controller.controller_path : nil
+ layout = find_by_parts(layout, formats, prefix, true)
+ end
+ content = _render_partial(options)
+ return _render_content_with_layout(content, layout, options[:locals])
+ end
+
+ def _deprecated_ivar_assign(template)
+ if respond_to?(:controller)
+ ivar = :"@#{template.variable_name}"
+ object =
+ if controller.instance_variable_defined?(ivar)
+ ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
+ controller.instance_variable_get(ivar),
+ "#{ivar} will no longer be implicitly assigned to #{template.variable_name}")
+ end
+ end
+ end
+
+ def _render_partial_with_block(layout, block, options)
+ @_proc_for_layout = block
+ concat(_render_partial(options.merge(:partial => layout)))
+ ensure
+ @_proc_for_layout = nil
+ end
+
+ def _render_partial_with_layout(layout, options)
+ if layout
+ prefix = controller && !layout.include?("/") ? controller.controller_path : nil
+ layout = find_by_parts(layout, formats, prefix, true)
+ end
+ content = _render_partial(options)
+ return _render_content_with_layout(content, layout, options[:locals])
+ end
+
+ def _deprecated_ivar_assign(template)
+ if respond_to?(:controller)
+ ivar = :"@#{template.variable_name}"
+ object =
+ if controller.instance_variable_defined?(ivar)
+ ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
+ controller.instance_variable_get(ivar),
+ "#{ivar} will no longer be implicitly assigned to #{template.variable_name}")
+ end
+ end
+ end
+
+ def _array_like_objects
+ array_like = [Array]
+ if defined?(ActiveRecord)
+ array_like.push(ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope)
+ end
+ array_like
+ end
+
+ def _render_partial_object(template, options, object = nil)
+ if options.key?(:collection)
+ _render_partial_collection(options.delete(:collection), options, template)
else
- if Array === partial_path ||
- (defined?(ActiveRecord) &&
- (ActiveRecord::Associations::AssociationCollection === partial_path ||
- ActiveRecord::NamedScope::Scope === partial_path))
- render_partial_collection(options.except(:partial).merge(:collection => partial_path))
- else
- object = partial_path
- render_partial(
- :partial => ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path),
- :object => object,
- :locals => local_assigns
- )
- end
+ locals = (options[:locals] ||= {})
+ object ||= locals[:object] || locals[template.variable_name]
+
+ _set_locals(object, locals, template, options)
+ _render_template(template, locals)
end
end
- def render_partial_collection(options = {}) #:nodoc:
- return nil if options[:collection].blank?
+ def _set_locals(object, locals, template, options)
+ object ||= _deprecated_ivar_assign(template)
+ locals[:object] = locals[template.variable_name] = object
+ locals[options[:as]] = object if options[:as]
+ end
+
+ def _render_partial_collection(collection, options = {}, passed_template = nil) #:nodoc:
+ return nil if collection.blank?
+
+ spacer = options[:spacer_template] ? _render_partial(:partial => options[:spacer_template]) : ''
- partial = options[:partial]
- spacer = options[:spacer_template] ? render(:partial => options[:spacer_template]) : ''
- local_assigns = options[:locals] ? options[:locals].clone : {}
- as = options[:as]
+ locals = (options[:locals] ||= {})
+ index, @_partial_path = 0, nil
+ collection.map do |object|
+ template = passed_template || begin
+ _partial_path =
+ ActionController::RecordIdentifier.partial_path(object, controller_path)
+ template = _pick_partial_template(_partial_path)
+ end
- index = 0
- options[:collection].map do |object|
- _partial_path ||= partial ||
- ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path)
- template = _pick_partial_template(_partial_path)
- local_assigns[template.counter_name] = index
- result = template.render_partial(self, object, local_assigns.dup, as)
+ _set_locals(object, locals, template, options)
+ locals[template.counter_name] = index
+
index += 1
- result
+ _render_template(template, locals)
end.join(spacer)
end
def _pick_partial_template(partial_path) #:nodoc:
- if partial_path.include?('/')
- path = File.join(File.dirname(partial_path), "_#{File.basename(partial_path)}")
- elsif controller
- path = "#{controller.class.controller_path}/_#{partial_path}"
- else
- path = "_#{partial_path}"
- end
-
- self.view_paths.find_template(path, self.template_format)
+ prefix = controller_path unless partial_path.include?('/')
+ find_by_parts(partial_path, formats, prefix, true)
end
memoize :_pick_partial_template
end
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
new file mode 100644
index 0000000000..a9b2acecd5
--- /dev/null
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -0,0 +1,114 @@
+module ActionView
+ module Rendering
+ # Returns the result of a render that's dictated by the options hash. The primary options are:
+ #
+ # * <tt>:partial</tt> - See ActionView::Partials.
+ # * <tt>:update</tt> - Calls update_page with the block given.
+ # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
+ # * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
+ # * <tt>:text</tt> - Renders the text passed in out.
+ #
+ # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
+ # as the locals hash.
+ def render(options = {}, local_assigns = {}, &block) #:nodoc:
+ local_assigns ||= {}
+
+ @exempt_from_layout = true
+
+ case options
+ when Hash
+ options[:locals] ||= {}
+ layout = options[:layout]
+
+ return _render_partial_with_layout(layout, options) if options.key?(:partial)
+ return _render_partial_with_block(layout, block, options) if block_given?
+
+ layout = find_by_parts(layout, formats) if layout
+
+ if file = options[:file]
+ template = find_by_parts(file, formats)
+ _render_template_with_layout(template, layout, :locals => options[:locals])
+ elsif inline = options[:inline]
+ _render_inline(inline, layout, options)
+ elsif text = options[:text]
+ _render_text(text, layout, options)
+ end
+ when :update
+ update_page(&block)
+ when String, NilClass
+ _render_partial(:partial => options, :locals => local_assigns)
+ end
+ end
+
+ def _render_content_with_layout(content, layout, locals)
+ return content unless layout
+
+ locals ||= {}
+
+ if controller && layout
+ response.layout = layout.path_without_format_and_extension if controller.respond_to?(:response)
+ logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger
+ end
+
+ begin
+ original_content_for_layout = @content_for_layout if defined?(@content_for_layout)
+ @content_for_layout = content
+
+ @cached_content_for_layout = @content_for_layout
+ _render_template(layout, locals)
+ ensure
+ @content_for_layout = original_content_for_layout
+ end
+ end
+
+ def _render_template(template, local_assigns = {})
+ with_template(template) do
+ _evaluate_assigns_and_ivars
+ _set_controller_content_type(template.mime_type) if template.respond_to?(:mime_type)
+
+ template.render(self, local_assigns) do |*names|
+ if !instance_variable_defined?(:"@content_for_#{names.first}") &&
+ instance_variable_defined?(:@_proc_for_layout) && (proc = @_proc_for_layout)
+ capture(*names, &proc)
+ elsif instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
+ instance_variable_get(ivar)
+ end
+ end
+ end
+ rescue Exception => e
+ raise e if template.is_a?(InlineTemplate) || !template.filename
+ if TemplateError === e
+ e.sub_template_of(template)
+ raise e
+ else
+ raise TemplateError.new(template, assigns, e)
+ end
+ end
+
+ def _render_inline(inline, layout, options)
+ content = _render_template(InlineTemplate.new(options[:inline], options[:type]), options[:locals] || {})
+ layout ? _render_content_with_layout(content, layout, options[:locals]) : content
+ end
+
+ def _render_text(text, layout, options)
+ layout ? _render_content_with_layout(text, layout, options[:locals]) : text
+ end
+
+ def _render_template_with_layout(template, layout = nil, options = {}, partial = false)
+ if controller && logger
+ logger.info("Rendering #{template.path_without_extension}" +
+ (options[:status] ? " (#{options[:status]})" : ''))
+ end
+
+ content = if partial
+ object = partial unless partial == true
+ _render_partial_object(template, options, object)
+ else
+ _render_template(template, options[:locals] || {})
+ end
+
+ return content unless layout && !template.exempt_from_layout?
+ _render_content_with_layout(content, layout, options[:locals] || {})
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_view/renderable_partial.rb b/actionpack/lib/action_view/renderable_partial.rb
deleted file mode 100644
index 3ea836fa25..0000000000
--- a/actionpack/lib/action_view/renderable_partial.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-module ActionView
- # NOTE: The template that this mixin is being included into is frozen
- # so you cannot set or modify any instance variables
- module RenderablePartial #:nodoc:
- extend ActiveSupport::Memoizable
-
- def variable_name
- name.sub(/\A_/, '').to_sym
- end
- memoize :variable_name
-
- def counter_name
- "#{variable_name}_counter".to_sym
- end
- memoize :counter_name
-
- def render(view, local_assigns = {})
- if defined? ActionController
- ActionController::Base.benchmark("Rendered #{path_without_format_and_extension}", Logger::DEBUG, false) do
- super
- end
- else
- super
- end
- end
-
- def render_partial(view, object = nil, local_assigns = {}, as = nil)
- object ||= local_assigns[:object] || local_assigns[variable_name]
-
- if object.nil? && view.respond_to?(:controller)
- ivar = :"@#{variable_name}"
- object =
- if view.controller.instance_variable_defined?(ivar)
- ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
- view.controller.instance_variable_get(ivar),
- "#{ivar} will no longer be implicitly assigned to #{variable_name}")
- end
- end
-
- # Ensure correct object is reassigned to other accessors
- local_assigns[:object] = local_assigns[variable_name] = object
- local_assigns[as] = object if as
-
- render_template(view, local_assigns)
- end
- end
-end
diff --git a/actionpack/lib/action_view/template_error.rb b/actionpack/lib/action_view/template/error.rb
index 37cb1c7c6c..37cb1c7c6c 100644
--- a/actionpack/lib/action_view/template_error.rb
+++ b/actionpack/lib/action_view/template/error.rb
diff --git a/actionpack/lib/action_view/template_handler.rb b/actionpack/lib/action_view/template/handler.rb
index 672da0ed2b..672da0ed2b 100644
--- a/actionpack/lib/action_view/template_handler.rb
+++ b/actionpack/lib/action_view/template/handler.rb
diff --git a/actionpack/lib/action_view/template_handlers.rb b/actionpack/lib/action_view/template/handlers.rb
index 205f8628f0..fb85f28851 100644
--- a/actionpack/lib/action_view/template_handlers.rb
+++ b/actionpack/lib/action_view/template/handlers.rb
@@ -1,8 +1,8 @@
module ActionView #:nodoc:
module TemplateHandlers #:nodoc:
- autoload :ERB, 'action_view/template_handlers/erb'
- autoload :RJS, 'action_view/template_handlers/rjs'
- autoload :Builder, 'action_view/template_handlers/builder'
+ autoload :ERB, 'action_view/template/handlers/erb'
+ autoload :RJS, 'action_view/template/handlers/rjs'
+ autoload :Builder, 'action_view/template/handlers/builder'
def self.extended(base)
base.register_default_template_handler :erb, TemplateHandlers::ERB
diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb
index 788dc93326..788dc93326 100644
--- a/actionpack/lib/action_view/template_handlers/builder.rb
+++ b/actionpack/lib/action_view/template/handlers/builder.rb
diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb
index e3120ba267..a20b1b0cd3 100644
--- a/actionpack/lib/action_view/template_handlers/erb.rb
+++ b/actionpack/lib/action_view/template/handlers/erb.rb
@@ -1,3 +1,5 @@
+require 'erb'
+
module ActionView
module TemplateHandlers
class ERB < TemplateHandler
diff --git a/actionpack/lib/action_view/template_handlers/rjs.rb b/actionpack/lib/action_view/template/handlers/rjs.rb
index 41a1fddb47..802a79b3fc 100644
--- a/actionpack/lib/action_view/template_handlers/rjs.rb
+++ b/actionpack/lib/action_view/template/handlers/rjs.rb
@@ -4,7 +4,7 @@ module ActionView
include Compilable
def compile(template)
- "@template_format = :html;" +
+ "@formats = [:html];" +
"controller.response.content_type ||= Mime::JS;" +
"update_page do |page|;#{template.source}\nend"
end
diff --git a/actionpack/lib/action_view/inline_template.rb b/actionpack/lib/action_view/template/inline.rb
index 54efa543c8..54efa543c8 100644
--- a/actionpack/lib/action_view/inline_template.rb
+++ b/actionpack/lib/action_view/template/inline.rb
diff --git a/actionpack/lib/action_view/template/partial.rb b/actionpack/lib/action_view/template/partial.rb
new file mode 100644
index 0000000000..30dec1dc5b
--- /dev/null
+++ b/actionpack/lib/action_view/template/partial.rb
@@ -0,0 +1,18 @@
+module ActionView
+ # NOTE: The template that this mixin is being included into is frozen
+ # so you cannot set or modify any instance variables
+ module RenderablePartial #:nodoc:
+ extend ActiveSupport::Memoizable
+
+ def variable_name
+ name.sub(/\A_/, '').to_sym
+ end
+ memoize :variable_name
+
+ def counter_name
+ "#{variable_name}_counter".to_sym
+ end
+ memoize :counter_name
+
+ end
+end
diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/template/renderable.rb
index ff7bc7d9de..0e8e0c4a38 100644
--- a/actionpack/lib/action_view/renderable.rb
+++ b/actionpack/lib/action_view/template/renderable.rb
@@ -6,6 +6,13 @@ module ActionView
module Renderable #:nodoc:
extend ActiveSupport::Memoizable
+ def render(view, locals)
+ compile(locals)
+ view.send(method_name(locals), locals) {|*args| yield(*args) }
+ end
+
+ private
+
def filename
'compiled-template'
end
@@ -18,30 +25,13 @@ module ActionView
def compiled_source
handler.call(self)
end
+ memoize :compiled_source
def method_name_without_locals
['_run', extension, method_segment].compact.join('_')
end
memoize :method_name_without_locals
- def render(view, local_assigns = {})
- compile(local_assigns)
-
- view.with_template self do
- view.send(:_evaluate_assigns_and_ivars)
- view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
-
- view.send(method_name(local_assigns), local_assigns) do |*names|
- ivar = :@_proc_for_layout
- if !view.instance_variable_defined?(:"@content_for_#{names.first}") && view.instance_variable_defined?(ivar) && (proc = view.instance_variable_get(ivar))
- view.capture(*names, &proc)
- elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
- view.instance_variable_get(ivar)
- end
- end
- end
- end
-
def method_name(local_assigns)
if local_assigns && local_assigns.any?
method_name = method_name_without_locals.dup
@@ -52,16 +42,16 @@ module ActionView
method_name.to_sym
end
- private
- # Compile and evaluate the template's code (if necessary)
- def compile(local_assigns)
- render_symbol = method_name(local_assigns)
+ # Compile and evaluate the template's code (if necessary)
+ def compile(local_assigns)
+ render_symbol = method_name(local_assigns)
- if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
- compile!(render_symbol, local_assigns)
- end
+ if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
+ compile!(render_symbol, local_assigns)
end
+ end
+ private
def compile!(render_symbol, local_assigns)
locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
@@ -75,8 +65,6 @@ module ActionView
begin
ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
- rescue Errno::ENOENT => e
- raise e # Missing template file, re-raise for Base to rescue
rescue Exception => e # errors from template code
if logger = defined?(ActionController) && Base.logger
logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template/template.rb
index a974f2652b..a61c46020f 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template/template.rb
@@ -6,7 +6,7 @@ module ActionView #:nodoc:
def initialize(path)
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
- @path = (path.ends_with?(File::SEPARATOR) ? path.to(-2) : path).freeze
+ @path = path.freeze
end
def to_s
@@ -38,28 +38,49 @@ module ActionView #:nodoc:
# should not be confused with format extensions +html+, +js+, +xml+,
# etc. A format must be supplied to match a formated file. +hello/index+
# will never match +hello/index.html.erb+.
- def [](path)
+ def find_template(path)
+ templates_in_path do |template|
+ if template.accessible_paths.include?(path)
+ return template
+ end
+ end
+ nil
end
- def load!
- end
+ def find_by_parts(name, extensions = nil, prefix = nil, partial = nil)
+ path = prefix ? "#{prefix}/" : ""
+
+ name = name.to_s.split("/")
+ name[-1] = "_#{name[-1]}" if partial
+
+ path << name.join("/")
+
+ template = nil
- def self.new_and_loaded(path)
- returning new(path) do |path|
- path.load!
+ Array(extensions).each do |extension|
+ extensioned_path = extension ? "#{path}.#{extension}" : path
+ template = find_template(extensioned_path) || find_template(path)
+ break if template
end
+ template || find_template(path)
end
-
+
private
- def relative_path_for_template_file(full_file_path)
- full_file_path.split("#{@path}/").last
+ def templates_in_path
+ (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
+ yield create_template(file) unless File.directory?(file)
+ end
+ end
+
+ def create_template(file)
+ Template.new(file.split("#{self}/").last, self)
end
end
class EagerPath < Path
- def load!
- return if @loaded
-
+ def initialize(path)
+ super
+
@paths = {}
templates_in_path do |template|
template.load!
@@ -68,24 +89,11 @@ module ActionView #:nodoc:
end
end
@paths.freeze
- @loaded = true
end
- def [](path)
- load! unless @loaded
+ def find_template(path)
@paths[path]
end
-
- private
- def templates_in_path
- (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
- yield create_template(file) unless File.directory?(file)
- end
- end
-
- def create_template(file)
- Template.new(relative_path_for_template_file(file), self)
- end
end
extend TemplateHandlers
@@ -107,8 +115,9 @@ module ActionView #:nodoc:
attr_accessor :locale, :name, :format, :extension
delegate :to_s, :to => :path
- def initialize(template_path, load_path = nil)
- @template_path, @load_path = template_path.dup, load_path
+ def initialize(template_path, load_paths = [])
+ template_path = template_path.dup
+ @load_path, @filename = find_full_path(template_path, load_paths)
@base_path, @name, @locale, @format, @extension = split(template_path)
@base_path.to_s.gsub!(/\/$/, '') # Push to split method
@@ -179,11 +188,10 @@ module ActionView #:nodoc:
@@exempt_from_layout.any? { |exempted| path =~ exempted }
end
- def filename
- # no load_path means this is an "absolute pathed" template
- load_path ? File.join(load_path, template_path) : template_path
+ def mtime
+ File.mtime(filename)
end
- memoize :filename
+ memoize :mtime
def source
File.read(filename)
@@ -195,20 +203,17 @@ module ActionView #:nodoc:
end
memoize :method_segment
- def render_template(view, local_assigns = {})
- render(view, local_assigns)
- rescue Exception => e
- raise e unless filename
- if TemplateError === e
- e.sub_template_of(self)
- raise e
- else
- raise TemplateError.new(self, view.assigns, e)
- end
+ def stale?
+ File.mtime(filename) > mtime
+ end
+
+ def recompile?
+ !@cached
end
def load!
- freeze
+ @cached = true
+ # freeze
end
private
@@ -217,30 +222,55 @@ module ActionView #:nodoc:
end
def valid_locale?(locale)
- locale && I18n.available_locales.include?(locale.to_sym)
+ I18n.available_locales.include?(locale.to_sym)
+ end
+
+ def find_full_path(path, load_paths)
+ load_paths = Array(load_paths) + [nil]
+ load_paths.each do |load_path|
+ file = load_path ? "#{load_path.to_str}/#{path}" : path
+ return load_path, file if File.file?(file)
+ end
+ raise MissingTemplate.new(load_paths, path)
end
# Returns file split into an array
# [base_path, name, locale, format, extension]
def split(file)
if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/)
- [m[1], m[2], *parse_extensions(m[3])]
+ base_path = m[1]
+ name = m[2]
+ extensions = m[3]
+ else
+ return
end
- end
- # returns parsed extensions as an array
- # [locale, format, extension]
- def parse_extensions(extensions)
- exts = extensions.split(".")
-
- if extension = valid_extension?(exts.last) && exts.pop || nil
- locale = valid_locale?(exts.first) && exts.shift || nil
- format = exts.join('.') if exts.any? # join('.') is needed for multipart templates
- else # no extension, just format
- format = exts.last
+ locale = nil
+ format = nil
+ extension = nil
+
+ if m = extensions.split(".")
+ if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three
+ locale = m[0]
+ format = m[1]
+ extension = m[2]
+ elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats
+ format = "#{m[0]}.#{m[1]}"
+ extension = m[2]
+ elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension
+ locale = m[0]
+ extension = m[1]
+ elsif valid_extension?(m[1]) # format and extension
+ format = m[0]
+ extension = m[1]
+ elsif valid_extension?(m[0]) # Just extension
+ extension = m[0]
+ else # No extension
+ format = m[0]
+ end
end
- [locale, format, extension]
+ [base_path, name, locale, format, extension]
end
end
end
diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb
new file mode 100644
index 0000000000..f81174d707
--- /dev/null
+++ b/actionpack/lib/action_view/template/text.rb
@@ -0,0 +1,9 @@
+module ActionView #:nodoc:
+ class TextTemplate < String #:nodoc:
+
+ def render(*) self end
+
+ def exempt_from_layout?() false end
+
+ end
+end
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index ec337bb05b..c8f204046b 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -7,18 +7,15 @@ module ActionView
@_rendered = { :template => nil, :partials => Hash.new(0) }
initialize_without_template_tracking(*args)
end
- end
-
- module Renderable
- alias_method :render_without_template_tracking, :render
- def render(view, local_assigns = {})
- if respond_to?(:path) && !is_a?(InlineTemplate)
- rendered = view.instance_variable_get(:@_rendered)
- rendered[:partials][self] += 1 if is_a?(RenderablePartial)
- rendered[:template] ||= self
+
+ alias_method :_render_template_without_template_tracking, :_render_template
+ def _render_template(template, local_assigns = {})
+ if template.respond_to?(:path) && !template.is_a?(InlineTemplate)
+ @_rendered[:partials][template] += 1 if template.is_a?(RenderablePartial)
+ @_rendered[:template] ||= template
end
- render_without_template_tracking(view, local_assigns)
- end
+ _render_template_without_template_tracking(template, local_assigns)
+ end
end
class TestCase < ActiveSupport::TestCase