diff options
Diffstat (limited to 'actionpack/lib')
37 files changed, 467 insertions, 303 deletions
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index 0ff1c0491a..dc9778a416 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -4,8 +4,6 @@ module AbstractController module Helpers extend ActiveSupport::Concern - include Rendering - included do class_attribute :_helpers self._helpers = Module.new diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index db6ff41f55..f78365afdb 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -46,34 +46,9 @@ module AbstractController module ClassMethods def view_context_class @view_context_class ||= begin - controller = self - Class.new(ActionView::Base) do - if controller.respond_to?(:_routes) && controller._routes - include controller._routes.url_helpers - include controller._routes.mounted_helpers - end - - if controller.respond_to?(:_helpers) - include controller._helpers - - # TODO: Fix RJS to not require this - self.helpers = controller._helpers - end - end - end - end - - def parent_prefixes - @parent_prefixes ||= begin - parent_controller = superclass - prefixes = [] - - until parent_controller.abstract? - prefixes << parent_controller.controller_path - parent_controller = parent_controller.superclass - end - - prefixes + routes = _routes if respond_to?(:_routes) + helpers = _helpers if respond_to?(:_helpers) + ActionView::Base.prepare(routes, helpers) end end end @@ -104,7 +79,7 @@ module AbstractController # Returns an object that is able to render templates. def view_renderer - @view_renderer ||= ActionView::Renderer.new(lookup_context, self) + @view_renderer ||= ActionView::Renderer.new(lookup_context) end # Normalize arguments, options and then delegates render_to_body and @@ -132,19 +107,7 @@ module AbstractController # Find and renders a template based on the options given. # :api: private def _render_template(options) #:nodoc: - if options.key?(:partial) - view_renderer.render_partial(view_context, options) - else - view_renderer.render_template(view_context, options) - end - end - - # The prefixes used in render "foo" shortcuts. - def _prefixes - @_prefixes ||= begin - parent_prefixes = self.class.parent_prefixes - parent_prefixes.dup.unshift(controller_path) - end + view_renderer.render(view_context, options) end private diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb index cea0f5ad1e..0893459e24 100644 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ b/actionpack/lib/abstract_controller/view_paths.rb @@ -11,11 +11,36 @@ module AbstractController delegate :find_template, :template_exists?, :view_paths, :formats, :formats=, :locale, :locale=, :to => :lookup_context + module ClassMethods + def parent_prefixes + @parent_prefixes ||= begin + parent_controller = superclass + prefixes = [] + + until parent_controller.abstract? + prefixes << parent_controller.controller_path + parent_controller = parent_controller.superclass + end + + prefixes + end + end + end + + # The prefixes used in render "foo" shortcuts. + def _prefixes + @_prefixes ||= begin + parent_prefixes = self.class.parent_prefixes + parent_prefixes.dup.unshift(controller_path) + end + end + # LookupContext is the object responsible to hold all information required to lookup # templates, i.e. view paths and details. Check ActionView::LookupContext for more # information. def lookup_context - @lookup_context ||= ActionView::LookupContext.new(self.class._view_paths, details_for_lookup) + @lookup_context ||= + ActionView::LookupContext.new(self.class._view_paths, details_for_lookup, _prefixes) end def details_for_lookup @@ -67,4 +92,4 @@ module AbstractController end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index aab2b9dc25..eba5e9377b 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -23,6 +23,7 @@ module ActionController autoload :ImplicitRender autoload :Instrumentation autoload :MimeResponds + autoload :ParamsWrapper autoload :RackDelegation autoload :Redirecting autoload :Renderers diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ca0dccf575..c03c77cb4a 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -206,13 +206,17 @@ module ActionController HttpAuthentication::Digest::ControllerMethods, HttpAuthentication::Token::ControllerMethods, + # Before callbacks should also be executed the earliest as possible, so + # also include them at the bottom. + AbstractController::Callbacks, + # Add instrumentations hooks at the bottom, to ensure they instrument # all the methods properly. Instrumentation, - # Before callbacks should also be executed the earliest as possible, so - # also include them at the bottom. - AbstractController::Callbacks, + # Params wrapper should come before instrumentation so they are + # properly showed in logs + ParamsWrapper, # The same with rescue, append it at the end to wrap as much as possible. Rescue diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb index dc3ea939e6..4e54c2ad88 100644 --- a/actionpack/lib/action_controller/metal/instrumentation.rb +++ b/actionpack/lib/action_controller/metal/instrumentation.rb @@ -14,7 +14,7 @@ module ActionController attr_internal :view_runtime - def process_action(action, *args) + def process_action(*args) raw_payload = { :controller => self.class.name, :action => self.action_name, diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb new file mode 100644 index 0000000000..21bbe17dc3 --- /dev/null +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -0,0 +1,224 @@ +require 'active_support/core_ext/class/attribute' +require 'active_support/core_ext/hash/slice' +require 'active_support/core_ext/hash/except' +require 'active_support/core_ext/array/wrap' +require 'action_dispatch/http/mime_types' + +module ActionController + # Wraps parameters hash into nested hash. This will allow client to submit + # POST request without having to specify a root element in it. + # + # By default this functionality won't be enabled. You can enable + # it globally by setting +ActionController::Base.wrap_parameters+: + # + # ActionController::Base.wrap_parameters = [:json] + # + # You could also turn it on per controller by setting the format array to + # non-empty array: + # + # class UsersController < ApplicationController + # wrap_parameters :format => [:json, :xml] + # end + # + # If you enable +ParamsWrapper+ for +:json+ format. Instead of having to + # send JSON parameters like this: + # + # {"user": {"name": "Konata"}} + # + # You can now just send a parameters like this: + # + # {"name": "Konata"} + # + # And it will be wrapped into a nested hash with the key name matching + # controller's name. For example, if you're posting to +UsersController+, + # your new +params+ hash will look like this: + # + # {"name" => "Konata", "user" => {"name" => "Konata"}} + # + # You can also specify the key in which the parameters should be wrapped to, + # and also the list of attributes it should wrap by using either +:only+ or + # +:except+ options like this: + # + # class UsersController < ApplicationController + # wrap_parameters :person, :only => [:username, :password] + # end + # + # If you're going to pass the parameters to an +ActiveModel+ object (such as + # +User.new(params[:user])+), you might consider passing the model class to + # the method instead. The +ParamsWrapper+ will actually try to determine the + # list of attribute names from the model and only wrap those attributes: + # + # class UsersController < ApplicationController + # wrap_parameters Person + # end + # + # You still could pass +:only+ and +:except+ to set the list of attributes + # you want to wrap. + # + # By default, if you don't specify the key in which the parameters would be + # wrapped to, +ParamsWrapper+ will actually try to determine if there's + # a model related to it or not. This controller, for example: + # + # class Admin::UsersController < ApplicationController + # end + # + # will try to check if +Admin::User+ or +User+ model exists, and use it to + # determine the wrapper key respectively. If both of the model doesn't exists, + # it will then fallback to use +user+ as the key. + module ParamsWrapper + extend ActiveSupport::Concern + + EXCLUDE_PARAMETERS = %w(authenticity_token _method utf8) + + included do + class_attribute :_wrapper_options + self._wrapper_options = {:format => []} + end + + module ClassMethods + # Sets the name of the wrapper key, or the model which +ParamsWrapper+ + # would use to determine the attribute names from. + # + # ==== Examples + # wrap_parameters :format => :xml + # # enables the parmeter wrapper for XML format + # + # wrap_parameters :person + # # wraps parameters into +params[:person]+ hash + # + # wrap_parameters Person + # # wraps parameters by determine the wrapper key from Person class + # (+person+, in this case) and the list of attribute names + # + # wrap_parameters :only => [:username, :title] + # # wraps only +:username+ and +:title+ attributes from parameters. + # + # wrap_parameters false + # # disable parameters wrapping for this controller altogether. + # + # ==== Options + # * <tt>:format</tt> - The list of formats in which the parameters wrapper + # will be enabled. + # * <tt>:only</tt> - The list of attribute names which parameters wrapper + # will wrap into a nested hash. + # * <tt>:except</tt> - The list of attribute names which parameters wrapper + # will exclude from a nested hash. + def wrap_parameters(name_or_model_or_options, options = {}) + model = nil + + case name_or_model_or_options + when Hash + options = name_or_model_or_options + when false + options = options.merge(:format => []) + when Symbol, String + options = options.merge(:name => name_or_model_or_options) + else + model = name_or_model_or_options + end + + _set_wrapper_defaults(_wrapper_options.slice(:format).merge(options), model) + end + + # Sets the default wrapper key or model which will be used to determine + # wrapper key and attribute names. Will be called automatically when the + # module is inherited. + def inherited(klass) + if klass._wrapper_options[:format].present? + klass._set_wrapper_defaults(klass._wrapper_options) + end + super + end + + protected + + # Determine the wrapper model from the controller's name. By convention, + # this could be done by trying to find the defined model that has the + # same singularize name as the controller. For example, +UsersController+ + # will try to find if the +User+ model exists. + def _default_wrap_model + model_name = self.name.sub(/Controller$/, '').singularize + + begin + model_klass = model_name.constantize + rescue NameError => e + unscoped_model_name = model_name.split("::", 2).last + break if unscoped_model_name == model_name + model_name = unscoped_model_name + end until model_klass + + model_klass + end + + def _set_wrapper_defaults(options, model=nil) + options = options.dup + + unless options[:only] || options[:except] + model ||= _default_wrap_model + if model.respond_to?(:column_names) + options[:only] = model.column_names + end + end + + unless options[:name] + model ||= _default_wrap_model + options[:name] = model ? model.to_s.demodulize.underscore : + controller_name.singularize + end + + options[:only] = Array.wrap(options[:only]).collect(&:to_s) if options[:only] + options[:except] = Array.wrap(options[:except]).collect(&:to_s) if options[:except] + options[:format] = Array.wrap(options[:format]) + + self._wrapper_options = options + end + end + + # Performs parameters wrapping upon the request. Will be called automatically + # by the metal call stack. + def process_action(*args) + if _wrapper_enabled? + wrapped_hash = _wrap_parameters request.request_parameters + wrapped_filtered_hash = _wrap_parameters request.filtered_parameters + + # This will make the wrapped hash accessible from controller and view + request.parameters.merge! wrapped_hash + request.request_parameters.merge! wrapped_hash + + # This will make the wrapped hash displayed in the log file + request.filtered_parameters.merge! wrapped_filtered_hash + end + super + end + + private + + # Returns the wrapper key which will use to stored wrapped parameters. + def _wrapper_key + _wrapper_options[:name] + end + + # Returns the list of enabled formats. + def _wrapper_formats + _wrapper_options[:format] + end + + # Returns the list of parameters which will be selected for wrapped. + def _wrap_parameters(parameters) + value = if only = _wrapper_options[:only] + parameters.slice(*only) + else + except = _wrapper_options[:except] || [] + parameters.except(*(except + EXCLUDE_PARAMETERS)) + end + + { _wrapper_key => value } + end + + # Checks if we should perform parameters wrapping. + def _wrapper_enabled? + ref = request.content_mime_type.try(:ref) + _wrapper_formats.include?(ref) && !request.request_parameters[_wrapper_key] + end + end +end diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index 59a3621f72..ebadb29ea7 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -68,7 +68,7 @@ module ActionController #:nodoc: # respond_with(@project, @task) # end # - # Giving an array of resources, you ensure that the responder will redirect to + # Giving several resources ensures that the responder will redirect to # <code>project_task_url</code> instead of <code>task_url</code>. # # Namespaced and singleton resources require a symbol to be given, as in @@ -77,6 +77,11 @@ module ActionController #:nodoc: # # respond_with(@project, :manager, @task) # + # Note that if you give an array, it will be treated as a collection, + # so the following is not equivalent: + # + # respond_with [@project, :manager, @task] + # # === Custom options # # <code>respond_with</code> also allow you to pass options that are forwarded diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 0dd847f967..3892a12407 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -2,17 +2,16 @@ require 'active_support/core_ext/file/path' require 'rack/chunked' module ActionController #:nodoc: - # Allow views to be streamed back to the client as they are rendered. + # Allows views to be streamed back to the client as they are rendered. # # The default way Rails renders views is by first rendering the template - # and then the layout. The first chunk of response is sent to the client - # just after the whole template is rendered, all queries are made and the - # layout is processed. + # and then the layout. The response is sent to the client after the whole + # template is rendered, all queries are made, and the layout is processed. # # Streaming inverts the rendering flow by rendering the layout first and # streaming each part of the layout as they are processed. This allows the - # header of the html (which is usually in the layout) to be streamed back - # to client very quickly, allowing javascripts and stylesheets to be loaded + # header of the HTML (which is usually in the layout) to be streamed back + # to client very quickly, allowing JavaScripts and stylesheets to be loaded # earlier than usual. # # This approach was introduced in Rails 3.1 and is still improving. Several @@ -20,13 +19,13 @@ module ActionController #:nodoc: # Those points are going to be addressed soon. # # In order to use streaming, you will need to use a Ruby version that - # supports Fibers (Fibers are supported since version 1.9.2 of the main + # supports fibers (fibers are supported since version 1.9.2 of the main # Ruby implementation). # # == Examples # # Streaming can be added to a controller easily, all you need to do is - # call stream at the controller class: + # call +stream+ in the controller class: # # class PostsController # stream @@ -42,19 +41,19 @@ module ActionController #:nodoc: # # class PostsController # def index - # @post = Post.scoped + # @posts = Post.scoped # render :stream => true # end # end # # == When to use streaming # - # Streaming may be considering an overkill for common actions like - # new or edit. The real benefit of streaming is on expensive actions - # that, for example, does a lot of queries on the database. + # Streaming may be considered to be overkill for lightweight actions like + # +new+ or +edit+. The real benefit of streaming is on expensive actions + # that, for example, do a lot of queries on the database. # # In such actions, you want to delay queries execution as much as you can. - # For example, imagine the following dashboard action: + # For example, imagine the following +dashboard+ action: # # def dashboard # @posts = Post.all @@ -63,10 +62,10 @@ module ActionController #:nodoc: # end # # Most of the queries here are happening in the controller. In order to benefit - # most of streaming, you would want to rewrite it as: + # from streaming you would want to rewrite it as: # # def dashboard - # # Allow lazily execution of the query + # # Allow lazy execution of the queries # @posts = Post.scoped # @pages = Page.scoped # @articles = Article.scoped @@ -75,12 +74,15 @@ module ActionController #:nodoc: # # == Communication between layout and template # - # When streaming, the layout is rendered first than the template. - # This means that, if your application currently rely on variables set - # in the template to be used in the layout, they won't work once you - # move to streaming. The proper way to communicate between layout and - # template, regardless if you use streaming or not, is by using - # +content_for+, +provide+ and +yield+. + # When streaming, rendering happens top-down instead of inside-out. + # Rails starts with the layout, and the template is rendered later, + # when its +yield+ is reached. + # + # This means that, if your application currently relies on instance + # variables set in the template to be used in the layout, they won't + # work once you move to streaming. The proper way to communicate + # between layout and template, regardless of whether you use streaming + # or not, is by using +content_for+, +provide+ and +yield+. # # Take a simple example where the layout expects the template to tell # which title to use: @@ -121,16 +123,16 @@ module ActionController #:nodoc: # and you want to use streaming, you would have to render the whole template # (and eventually trigger all queries) before streaming the title and all # assets, which kills the purpose of streaming. For this reason Rails 3.1 - # introduces a helper called +provide+ that does the same as +content_for+ + # introduces a new helper called +provide+ that does the same as +content_for+ # but tells the layout to stop searching for other entries and continue rendering. # - # For instance, the template below, using +provide+: + # For instance, the template above using +provide+ would be: # # <%= provide :title, "Main" %> # Hello # <%= content_for :title, " page" %> # - # Has as final result: + # Giving: # # <html> # <head><title>Main</title></head> @@ -138,27 +140,27 @@ module ActionController #:nodoc: # </html> # # That said, when streaming, you need to properly check your templates - # and chose when to use +provide+ and +content_for+. + # and choose when to use +provide+ and +content_for+. # # == Headers, cookies, session and flash # # When streaming, the HTTP headers are sent to the client right before # it renders the first line. This means that, modifying headers, cookies, - # session or flash after the template start rendering will not propagate + # session or flash after the template starts rendering will not propagate # to the client. # - # If you try to modify cookies, session or flash, a ClosedError will be - # raised, showing those objects are closed for modification. + # If you try to modify cookies, session or flash, an +ActionDispatch::ClosedError+ + # will be raised, showing those objects are closed for modification. # # == Middlewares # # Middlewares that need to manipulate the body won't work with streaming. # You should disable those middlewares whenever streaming in development - # or production. For instance, Rack::Bug won't work when streaming as it + # or production. For instance, +Rack::Bug+ won't work when streaming as it # needs to inject contents in the HTML body. # - # Also Rack::Cache won't work with streaming as it does not support - # streaming bodies yet. So, whenever streaming, Cache-Control is automatically + # Also +Rack::Cache+ won't work with streaming as it does not support + # streaming bodies yet. Whenever streaming Cache-Control is automatically # set to "no-cache". # # == Errors @@ -193,10 +195,10 @@ module ActionController #:nodoc: # # unicorn_rails --config-file unicorn.config.rb # - # You may also want to configure other parameters like :tcp_nodelay. Please - # check its documentation for more information: http://unicorn.bogomips.org/Unicorn/Configurator.html#method-i-listen + # You may also want to configure other parameters like <tt>:tcp_nodelay</tt>. + # Please check its documentation for more information: http://unicorn.bogomips.org/Unicorn/Configurator.html#method-i-listen # - # If you are using unicorn with nginx, you may need to tweak nginx. + # If you are using Unicorn with Nginx, you may need to tweak Nginx. # Streaming should work out of the box on Rainbows. # # ==== Passenger diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 68ba1a81b5..980c658ab7 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -1,6 +1,13 @@ module ActionDispatch module Http module MimeNegotiation + extend ActiveSupport::Concern + + included do + mattr_accessor :ignore_accept_header + self.ignore_accept_header = false + end + # The MIME type of the HTTP request, such as Mime::XML. # # For backward compatibility, the post \format is extracted from the @@ -42,16 +49,14 @@ module ActionDispatch formats.first end - BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ - def formats - accept = @env['HTTP_ACCEPT'] - @env["action_dispatch.request.formats"] ||= if parameters[:format] Array(Mime[parameters[:format]]) - elsif xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS) + elsif use_accept_header && valid_accept_header accepts + elsif xhr? + [Mime::JS] else [Mime::HTML] end @@ -87,6 +92,18 @@ module ActionDispatch order.include?(Mime::ALL) ? formats.first : nil end + + protected + + BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ + + def valid_accept_header + xhr? || (accept && accept !~ BROWSER_LIKE_ACCEPTS) + end + + def use_accept_header + !self.class.ignore_accept_header + end end end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index f07ac44f7a..ccb866f4f7 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -17,16 +17,17 @@ module ActionDispatch include ActionDispatch::Http::Upload include ActionDispatch::Http::URL - LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze - - %w[ AUTH_TYPE GATEWAY_INTERFACE + LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze + ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE PATH_TRANSLATED REMOTE_HOST REMOTE_IDENT REMOTE_USER REMOTE_ADDR SERVER_NAME SERVER_PROTOCOL HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM - HTTP_NEGOTIATE HTTP_PRAGMA ].each do |env| + HTTP_NEGOTIATE HTTP_PRAGMA ].freeze + + ENV_METHODS.each do |env| class_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{env.sub(/^HTTP_/n, '').downcase} @env["#{env}"] diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index ac0fd9607d..d9c07d6ca3 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -165,7 +165,7 @@ module ActionDispatch # such as 2 to catch <tt>["www"]</tt> instead of <tt>"www.rubyonrails"</tt> # in "www.rubyonrails.co.uk". def subdomain(tld_length = @@tld_length) - subdomains(tld_length) + subdomains(tld_length).join(".") end end end diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index 9c9ccc62f5..8ebf870b95 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -59,7 +59,7 @@ module ActionDispatch end def set_session(env, sid, session_data, options) - persistent_session_id!(session_data, sid) + session_data.merge("session_id" => sid) end def set_cookie(env, session_id, cookie) diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index b1adf3d2d1..c17c746096 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -116,7 +116,7 @@ module ActionDispatch end def render(status, body) - [status, {'Content-Type' => 'text/html', 'Content-Length' => body.bytesize.to_s}, [body]] + [status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]] end def public_path diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb index 348f7b86b8..404943d720 100644 --- a/actionpack/lib/action_dispatch/middleware/static.rb +++ b/actionpack/lib/action_dispatch/middleware/static.rb @@ -2,10 +2,10 @@ require 'rack/utils' module ActionDispatch class FileHandler - def initialize(root) + def initialize(root, cache_control) @root = root.chomp('/') @compiled_root = /^#{Regexp.escape(root)}/ - @file_server = ::Rack::File.new(@root) + @file_server = ::Rack::File.new(@root, cache_control) end def match?(path) @@ -35,18 +35,15 @@ module ActionDispatch end class Static - FILE_METHODS = %w(GET HEAD).freeze - - def initialize(app, path) + def initialize(app, path, cache_control=nil) @app = app - @file_handler = FileHandler.new(path) + @file_handler = FileHandler.new(path, cache_control) end def call(env) - path = env['PATH_INFO'].chomp('/') - method = env['REQUEST_METHOD'] - - if FILE_METHODS.include?(method) + case env['REQUEST_METHOD'] + when 'GET', 'HEAD' + path = env['PATH_INFO'].chomp('/') if match = @file_handler.match?(path) env["PATH_INFO"] = match return @file_handler.call(env) diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb index 97f7cf0bbe..0c5bafa666 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb @@ -24,7 +24,7 @@ <div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div> <p><a href="#" onclick="document.getElementById('env_dump').style.display='block'; return false;">Show env dump</a></p> -<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env %></pre></div> +<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div> <h2 style="margin-top: 30px">Response</h2> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb index 6c32fb17b8..6e71fd7ddc 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb @@ -1,11 +1,13 @@ -<html xmlns="http://www.w3.org/1999/xhtml"> +<!DOCTYPE html> +<html lang="en"> <head> + <meta charset="utf-8" /> <title>Action Controller: Exception caught</title> <style> body { background-color: #fff; color: #333; } body, p, ol, ul, td { - font-family: verdana, arial, helvetica, sans-serif; + font-family: helvetica, verdana, arial, sans-serif; font-size: 13px; line-height: 18px; } diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 0a3bd5fe40..f51cc3711b 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -9,10 +9,12 @@ module ActionDispatch config.action_dispatch.show_exceptions = true config.action_dispatch.best_standards_support = true config.action_dispatch.tld_length = 1 + config.action_dispatch.ignore_accept_header = false config.action_dispatch.rack_cache = {:metastore => "rails:/", :entitystore => "rails:/", :verbose => true} initializer "action_dispatch.configure" do |app| ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length + ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header end end end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 1d09091dc7..97e8ccc9a5 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -3,6 +3,7 @@ require 'forwardable' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/to_query' require 'active_support/core_ext/hash/slice' +require 'active_support/core_ext/module/remove_method' module ActionDispatch module Routing @@ -160,7 +161,7 @@ module ActionDispatch # We use module_eval to avoid leaks @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 - remove_method :#{selector} if method_defined?(:#{selector}) + remove_possible_method :#{selector} def #{selector}(*args) options = args.extract_options! @@ -194,7 +195,7 @@ module ActionDispatch hash_access_method = hash_access_name(name, kind) @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 - remove_method :#{selector} if method_defined?(:#{selector}) + remove_possible_method :#{selector} def #{selector}(*args) url_for(#{hash_access_method}(*args)) end @@ -240,6 +241,11 @@ module ActionDispatch end def eval_block(block) + if block.arity == 1 + raise "You are using the old router DSL which has been removed in Rails 3.1. " << + "Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/ " << + "or add the rails_legacy_mapper gem to your Gemfile" + end mapper = Mapper.new(self) if default_scope mapper.with_default_scope(default_scope, &block) diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index e209978fb7..3335742d47 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -42,7 +42,7 @@ module ActionDispatch elsif type.is_a?(Symbol) && @response.response_code == Rack::Utils::SYMBOL_TO_STATUS_CODE[type] assert_block("") { true } # to count the assertion else - assert(false, build_message(message, "Expected response to be a <?>, but was <?>", type, @response.response_code)) + flunk(build_message(message, "Expected response to be a <?>, but was <?>", type, @response.response_code)) end end diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb index 170ceb299a..584e5c3791 100644 --- a/actionpack/lib/action_pack/version.rb +++ b/actionpack/lib/action_pack/version.rb @@ -3,7 +3,7 @@ module ActionPack MAJOR = 3 MINOR = 1 TINY = 0 - PRE = "beta" + PRE = "beta1" STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index ca0a89c8a5..c98110353f 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -156,41 +156,45 @@ module ActionView #:nodoc: def cache_template_loading=(value) ActionView::Resolver.caching = value end + + def process_view_paths(value) + value.is_a?(PathSet) ? + value.dup : ActionView::PathSet.new(Array.wrap(value)) + end + + def xss_safe? #:nodoc: + true + end + + # This method receives routes and helpers from the controller + # and return a subclass ready to be used as view context. + def prepare(routes, helpers) #:nodoc: + Class.new(self) do + if routes + include routes.url_helpers + include routes.mounted_helpers + end + + if helpers + include helpers + self.helpers = helpers + end + end + end end attr_accessor :view_renderer - attr_internal :request, :controller, :config, :assigns + attr_internal :config, :assigns delegate :lookup_context, :to => :view_renderer delegate :formats, :formats=, :locale, :locale=, :view_paths, :view_paths=, :to => :lookup_context - delegate :request_forgery_protection_token, :params, :session, :cookies, :response, :headers, - :flash, :action_name, :controller_name, :to => :controller - - delegate :logger, :to => :controller, :allow_nil => true - - def self.xss_safe? #:nodoc: - true - end - - def self.process_view_paths(value) - value.is_a?(PathSet) ? - value.dup : ActionView::PathSet.new(Array.wrap(value)) - end - def assign(new_assigns) # :nodoc: @_assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) } end - def initialize(context = nil, assigns_for_first_render = {}, controller = nil, formats = nil) #:nodoc: - assign(assigns_for_first_render) - self.helpers = Module.new unless self.class.helpers - + def initialize(context = nil, assigns = {}, controller = nil, formats = nil) #:nodoc: @_config = {} - if @_controller = controller - @_request = controller.request if controller.respond_to?(:request) - @_config = controller.config.inheritable_copy if controller.respond_to?(:config) - end # Handle all these for backwards compatibility. # TODO Provide a new API for AV::Base and deprecate this one. @@ -199,18 +203,16 @@ module ActionView #:nodoc: elsif lookup_context = context.is_a?(ActionView::LookupContext) ? context : ActionView::LookupContext.new(context) - lookup_context.formats = formats if formats - @view_renderer = ActionView::Renderer.new(lookup_context, controller) + lookup_context.formats = formats if formats + lookup_context.prefixes = controller._prefixes if controller + @view_renderer = ActionView::Renderer.new(lookup_context) end + assign(assigns) + assign_controller(controller) _prepare_context end - # TODO Is this needed anywhere? Maybe deprecate it? - def controller_path - @controller_path ||= controller && controller.controller_path - end - ActiveSupport.run_load_hooks(:action_view, self) end end diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb index 3ef9826d30..78a68db282 100644 --- a/actionpack/lib/action_view/helpers.rb +++ b/actionpack/lib/action_view/helpers.rb @@ -9,6 +9,7 @@ module ActionView #:nodoc: autoload :AtomFeedHelper autoload :CacheHelper autoload :CaptureHelper + autoload :ControllerHelper autoload :CsrfHelper autoload :DateHelper autoload :DebugHelper @@ -39,6 +40,7 @@ module ActionView #:nodoc: include AtomFeedHelper include CacheHelper include CaptureHelper + include ControllerHelper include CsrfHelper include DateHelper include DebugHelper diff --git a/actionpack/lib/action_view/helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_paths.rb index cb6737b94e..958f0e0a10 100644 --- a/actionpack/lib/action_view/helpers/asset_paths.rb +++ b/actionpack/lib/action_view/helpers/asset_paths.rb @@ -21,7 +21,6 @@ module ActionView return source if is_uri?(source) source = rewrite_extension(source, dir, ext) if ext - source = "/#{dir}/#{source}" unless source[0] == ?/ source = rewrite_asset_path(source, dir) if controller && include_host diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb index 38860431b4..cd0f8c8878 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb @@ -41,7 +41,8 @@ module ActionView # Break out the asset path rewrite in case plugins wish to put the asset id # someplace other than the query string. - def rewrite_asset_path(source, path = nil) + def rewrite_asset_path(source, dir) + source = "/#{dir}/#{source}" unless source[0] == ?/ path = config.asset_path if path && path.respond_to?(:call) diff --git a/actionpack/lib/action_view/helpers/controller_helper.rb b/actionpack/lib/action_view/helpers/controller_helper.rb new file mode 100644 index 0000000000..e22331cb3c --- /dev/null +++ b/actionpack/lib/action_view/helpers/controller_helper.rb @@ -0,0 +1,21 @@ +module ActionView + module Helpers + # This module keeps all methods and behavior in ActionView + # that simply delegates to the controller. + module ControllerHelper #:nodoc: + attr_internal :controller, :request + + delegate :request_forgery_protection_token, :params, :session, :cookies, :response, :headers, + :flash, :action_name, :controller_name, :controller_path, :to => :controller + + delegate :logger, :to => :controller, :allow_nil => true + + def assign_controller(controller) + if @_controller = controller + @_request = controller.request if controller.respond_to?(:request) + @_config = controller.config.inheritable_copy if controller.respond_to?(:config) + end + end + end + end +end
\ No newline at end of file diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 49aa434020..9e0f8f32b7 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -74,6 +74,8 @@ module ActionView # ==== Options # * <tt>:multiple</tt> - If set to true the selection will allow multiple choices. # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input. + # * <tt>:include_blank</tt> - If set to true, an empty option will be create + # * <tt>:prompt</tt> - Create a prompt option with blank value and the text asking user to select something # * Any other key creates standard HTML attributes for the tag. # # ==== Examples @@ -99,18 +101,26 @@ module ActionView # # => <select class="form_input" id="access" multiple="multiple" name="access[]"><option>Read</option> # # <option>Write</option></select> # + # select_tag "people", options_from_collection_for_select(@people, "id", "name"), :include_blank => true + # # => <select id="people" name="people"><option value=""></option><option value="1">David</option></select> + # + # select_tag "people", options_from_collection_for_select(@people, "id", "name"), :prompt => "Select something" + # # => <select id="people" name="people"><option value="">Select something</option><option value="1">David</option></select> + # # select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>", :disabled => true # # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option> # # <option>Paris</option><option>Rome</option></select> def select_tag(name, option_tags = nil, options = {}) html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name - if blank = options.delete(:include_blank) - if blank.kind_of?(String) - option_tags = "<option value=\"\">#{blank}</option>".html_safe + option_tags - else - option_tags = "<option value=\"\"></option>".html_safe + option_tags - end + + if options.delete(:include_blank) + option_tags = "<option value=\"\"></option>".html_safe + option_tags + end + + if prompt = options.delete(:prompt) + option_tags = "<option value=\"\">#{prompt}</option>".html_safe + option_tags end + content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys) end diff --git a/actionpack/lib/action_view/helpers/rendering_helper.rb b/actionpack/lib/action_view/helpers/rendering_helper.rb index c91e03b7e8..47efdded42 100644 --- a/actionpack/lib/action_view/helpers/rendering_helper.rb +++ b/actionpack/lib/action_view/helpers/rendering_helper.rb @@ -20,10 +20,8 @@ module ActionView when Hash if block_given? view_renderer.render_partial(self, options.merge(:partial => options[:layout]), &block) - elsif options.key?(:partial) - view_renderer.render_partial(self, options) else - view_renderer.render_template(self, options) + view_renderer.render(self, options) end else view_renderer.render_partial(self, :partial => options, :locals => locals) diff --git a/actionpack/lib/action_view/helpers/sprockets_helper.rb b/actionpack/lib/action_view/helpers/sprockets_helper.rb index b43b91178c..ab98da9624 100644 --- a/actionpack/lib/action_view/helpers/sprockets_helper.rb +++ b/actionpack/lib/action_view/helpers/sprockets_helper.rb @@ -40,10 +40,10 @@ module ActionView class AssetPaths < ActionView::Helpers::AssetPaths #:nodoc: def rewrite_asset_path(source, dir) - if source =~ /^\/#{dir}\/(.+)/ - assets.path($1, performing_caching?, dir) - else + if source[0] == ?/ source + else + assets.path(source, performing_caching?, dir) end end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 06e2b027da..ca09c77b5c 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -265,60 +265,6 @@ module ActionView text.html_safe.safe_concat("</p>") end - # Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option - # will limit what should be linked. You can add HTML attributes to the links using - # <tt>:html</tt>. Possible values for <tt>:link</tt> are <tt>:all</tt> (default), - # <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and - # e-mail address is yielded and the result is used as the link text. - # - # ==== Examples - # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com") - # # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and - # # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>" - # - # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls) - # # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a> - # # or e-mail david@loudthinking.com" - # - # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses) - # # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>" - # - # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com." - # auto_link(post_body, :html => { :target => '_blank' }) do |text| - # truncate(text, :length => 15) - # end - # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>. - # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>." - # - # - # You can still use <tt>auto_link</tt> with the old API that accepts the - # +link+ as its optional second parameter and the +html_options+ hash - # as its optional third parameter: - # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com." - # auto_link(post_body, :urls) - # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>. - # Please e-mail me at me@email.com." - # - # auto_link(post_body, :all, :target => "_blank") - # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>. - # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>." - def auto_link(text, *args, &block)#link = :all, html = {}, &block) - return '' if text.blank? - - options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter - unless args.empty? - options[:link] = args[0] || :all - options[:html] = args[1] || {} - end - options.reverse_merge!(:link => :all, :html => {}) - - case options[:link].to_sym - when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block) - when :email_addresses then auto_link_email_addresses(text, options[:html], &block) - when :urls then auto_link_urls(text, options[:html], options, &block) - end - end - # Creates a Cycle object whose _to_s_ method cycles through elements of an # array every time it is called. This can be used for example, to alternate # classes for table rows. You can use named cycles to allow nesting in loops. @@ -464,77 +410,6 @@ module ActionView @_cycles = Hash.new unless defined?(@_cycles) @_cycles[name] = cycle_object end - - AUTO_LINK_RE = %r{ - (?: ([0-9A-Za-z+.:-]+:)// | www\. ) - [^\s<]+ - }x - - # regexps for determining context, used high-volume - AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i] - - AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/ - - BRACKETS = { ']' => '[', ')' => '(', '}' => '{' } - - # Turns all urls into clickable links. If a block is given, each url - # is yielded and the result is used as the link text. - def auto_link_urls(text, html_options = {}, options = {}) - link_attributes = html_options.stringify_keys - text.gsub(AUTO_LINK_RE) do - scheme, href = $1, $& - punctuation = [] - - if auto_linked?($`, $') - # do not change string; URL is already linked - href - else - # don't include trailing punctuation character as part of the URL - while href.sub!(/[^\w\/-]$/, '') - punctuation.push $& - if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size - href << punctuation.pop - break - end - end - - link_text = block_given?? yield(href) : href - href = 'http://' + href unless scheme - - unless options[:sanitize] == false - link_text = sanitize(link_text) - href = sanitize(href) - end - content_tag(:a, link_text, link_attributes.merge('href' => href), !!options[:sanitize]) + punctuation.reverse.join('') - end - end - end - - # Turns all email addresses into clickable links. If a block is given, - # each email is yielded and the result is used as the link text. - def auto_link_email_addresses(text, html_options = {}, options = {}) - text.gsub(AUTO_EMAIL_RE) do - text = $& - - if auto_linked?($`, $') - text.html_safe - else - display_text = (block_given?) ? yield(text) : text - - unless options[:sanitize] == false - text = sanitize(text) - display_text = sanitize(display_text) unless text == display_text - end - mail_to text, display_text, html_options - end - end - end - - # Detects already linked context or position in the middle of a tag - def auto_linked?(left, right) - (left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or - (left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3]) - end end end end diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 06c607931d..06975ffa2f 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -9,6 +9,8 @@ module ActionView # generate a key, given to view paths, used in the resolver cache lookup. Since # this key is generated just once during the request, it speeds up all cache accesses. class LookupContext #:nodoc: + attr_accessor :prefixes + mattr_accessor :fallbacks @@fallbacks = FallbackFileSystemResolver.instances @@ -58,10 +60,11 @@ module ActionView end end - def initialize(view_paths, details = {}) + def initialize(view_paths, details = {}, prefixes = []) @details, @details_key = { :handlers => default_handlers }, nil @frozen_formats, @skip_default_locale = false, false @cache = true + @prefixes = prefixes self.view_paths = view_paths self.registered_detail_setters.each do |key, setter| diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb index f20ba7e6d3..80391d72cc 100644 --- a/actionpack/lib/action_view/railtie.rb +++ b/actionpack/lib/action_view/railtie.rb @@ -6,7 +6,7 @@ module ActionView class Railtie < Rails::Railtie config.action_view = ActiveSupport::OrderedOptions.new config.action_view.stylesheet_expansions = {} - config.action_view.javascript_expansions = { :defaults => %w(jquery rails) } + config.action_view.javascript_expansions = { :defaults => %w(jquery jquery_ujs) } initializer "action_view.cache_asset_ids" do |app| unless app.config.cache_classes diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb index d389105a7a..60c527beeb 100644 --- a/actionpack/lib/action_view/renderer/abstract_renderer.rb +++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb @@ -3,9 +3,8 @@ module ActionView delegate :find_template, :template_exists?, :with_fallbacks, :update_details, :with_layout_format, :formats, :freeze_formats, :to => :@lookup_context - def initialize(lookup_context, controller) + def initialize(lookup_context) @lookup_context = lookup_context - @controller = controller end def render diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 70327b16c4..a351fbc04f 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -219,7 +219,7 @@ module ActionView def initialize(*) super - @partial_names = PARTIAL_NAMES[@controller.class.name] + @partial_names = PARTIAL_NAMES[@lookup_context.prefixes.first] end def render(context, options, block) @@ -304,10 +304,6 @@ module ActionView self end - def controller_prefixes - @controller_prefixes ||= @controller && @controller._prefixes - end - def collection if @options.key?(:collection) collection = @options[:collection] @@ -331,7 +327,7 @@ module ActionView end def find_template(path=@path, locals=@locals.keys) - prefixes = path.include?(?/) ? [] : controller_prefixes + prefixes = path.include?(?/) ? [] : @lookup_context.prefixes @lookup_context.find_template(path, prefixes, true, locals) end @@ -372,7 +368,7 @@ module ActionView object = object.to_model if object.respond_to?(:to_model) object.class.model_name.partial_path.dup.tap do |partial| - path = controller_prefixes.first + path = @lookup_context.prefixes.first partial.insert(0, "#{File.dirname(path)}/") if partial.include?(?/) && path.include?(?/) end end diff --git a/actionpack/lib/action_view/renderer/renderer.rb b/actionpack/lib/action_view/renderer/renderer.rb index 3c0126f6bb..bf1b5a7d22 100644 --- a/actionpack/lib/action_view/renderer/renderer.rb +++ b/actionpack/lib/action_view/renderer/renderer.rb @@ -3,11 +3,19 @@ module ActionView # to other objects like TemplateRenderer and PartialRenderer which # actually renders the template. class Renderer - attr_accessor :lookup_context, :controller + attr_accessor :lookup_context - def initialize(lookup_context, controller) + def initialize(lookup_context) @lookup_context = lookup_context - @controller = controller + end + + # Main render entry point shared by AV and AC. + def render(context, options) + if options.key?(:partial) + render_partial(context, options) + else + render_template(context, options) + end end # Render but returns a valid Rack body. If fibers are defined, we return @@ -19,7 +27,7 @@ module ActionView if options.key?(:partial) [render_partial(context, options)] else - StreamingTemplateRenderer.new(@lookup_context, @controller).render(context, options) + StreamingTemplateRenderer.new(@lookup_context).render(context, options) end end @@ -36,11 +44,11 @@ module ActionView private def _template_renderer #:nodoc: - @_template_renderer ||= TemplateRenderer.new(@lookup_context, @controller) + @_template_renderer ||= TemplateRenderer.new(@lookup_context) end def _partial_renderer #:nodoc: - @_partial_renderer ||= PartialRenderer.new(@lookup_context, @controller) + @_partial_renderer ||= PartialRenderer.new(@lookup_context) end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb index 6c55a865a1..a09cef8fef 100644 --- a/actionpack/lib/action_view/renderer/template_renderer.rb +++ b/actionpack/lib/action_view/renderer/template_renderer.rb @@ -20,7 +20,7 @@ module ActionView if options.key?(:text) Template::Text.new(options[:text], formats.try(:first)) elsif options.key?(:file) - with_fallbacks { find_template(options[:file], options[:prefixes], false, keys) } + with_fallbacks { find_template(options[:file], nil, false, keys) } elsif options.key?(:inline) handler = Template.handler_for_extension(options[:type] || "erb") Template.new(options[:inline], "inline template", handler, :locals => keys) diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 14e032790d..d0317a148b 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -1,4 +1,6 @@ require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/module/remove_method' require 'action_controller' require 'action_controller/test_case' require 'action_view' @@ -43,6 +45,7 @@ module ActionView include AbstractController::Helpers include ActionView::Helpers + delegate :lookup_context, :to => :controller attr_accessor :controller, :output_buffer, :rendered module ClassMethods @@ -127,7 +130,7 @@ module ActionView def say_no_to_protect_against_forgery! _helpers.module_eval do - remove_method :protect_against_forgery? if method_defined?(:protect_against_forgery?) + remove_possible_method :protect_against_forgery? def protect_against_forgery? false end |