aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller/base.rb38
-rw-r--r--actionpack/lib/abstract_controller/callbacks.rb4
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb6
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb28
-rw-r--r--actionpack/lib/abstract_controller/view_paths.rb2
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb4
-rw-r--r--actionpack/lib/action_controller/metal/compatibility.rb11
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb16
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb2
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb20
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb5
-rw-r--r--actionpack/lib/action_controller/metal/responder.rb7
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb26
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb9
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb56
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb2
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb9
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb2
-rw-r--r--actionpack/lib/action_pack/version.rb2
-rw-r--r--actionpack/lib/action_view.rb1
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb53
-rw-r--r--actionpack/lib/action_view/lookup_context.rb10
-rw-r--r--actionpack/lib/action_view/path_set.rb2
-rw-r--r--actionpack/lib/action_view/template/error.rb2
-rw-r--r--actionpack/lib/action_view/template/resolver.rb62
-rw-r--r--actionpack/lib/sprockets/railtie.rb12
29 files changed, 268 insertions, 135 deletions
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index 0951267fea..f67d0e558e 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -130,27 +130,39 @@ module AbstractController
self.class.action_methods
end
- # Returns true if the name can be considered an action. This can
- # be overridden in subclasses to modify the semantics of what
- # can be considered an action.
+ # Returns true if a method for the action is available and
+ # can be dispatched, false otherwise.
#
- # For instance, this is overriden by ActionController to add
- # the implicit rendering feature.
- #
- # ==== Parameters
- # * <tt>name</tt> - The name of an action to be tested
- #
- # ==== Returns
- # * <tt>TrueClass</tt>, <tt>FalseClass</tt>
- def action_method?(name)
- self.class.action_methods.include?(name)
+ # Notice that <tt>action_methods.include?("foo")</tt> may return
+ # false and <tt>available_action?("foo")</tt> returns true because
+ # available action consider actions that are also available
+ # through other means, for example, implicit render ones.
+ def available_action?(action_name)
+ method_for_action(action_name).present?
end
private
+ # Returns true if the name can be considered an action because
+ # it has a method defined in the controller.
+ #
+ # ==== Parameters
+ # * <tt>name</tt> - The name of an action to be tested
+ #
+ # ==== Returns
+ # * <tt>TrueClass</tt>, <tt>FalseClass</tt>
+ #
+ # :api: private
+ def action_method?(name)
+ self.class.action_methods.include?(name)
+ end
+
# Call the action. Override this in a subclass to modify the
# behavior around processing an action. This, and not #process,
# is the intended way to override action dispatching.
+ #
+ # Notice that the first argument is the method to be dispatched
+ # which is *not* necessarily the same as the action name.
def process_action(method_name, *args)
send_action(method_name, *args)
end
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb
index f7b2b7ff53..e8426bc52b 100644
--- a/actionpack/lib/abstract_controller/callbacks.rb
+++ b/actionpack/lib/abstract_controller/callbacks.rb
@@ -13,8 +13,8 @@ module AbstractController
# Override AbstractController::Base's process_action to run the
# process_action callbacks around the normal behavior.
- def process_action(method_name, *args)
- run_callbacks(:process_action, method_name) do
+ def process_action(*args)
+ run_callbacks(:process_action, action_name) do
super
end
end
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index d1b87b67ee..8f73e244d7 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -292,15 +292,15 @@ module AbstractController
end
end
- attr_writer :action_has_layout
+ attr_internal_writer :action_has_layout
def initialize(*)
- @action_has_layout = true
+ @_action_has_layout = true
super
end
def action_has_layout?
- @action_has_layout
+ @_action_has_layout
end
private
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index f78365afdb..ab2c532859 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -32,9 +32,13 @@ module AbstractController
module Rendering
extend ActiveSupport::Concern
-
include AbstractController::ViewPaths
+ included do
+ config_accessor :protected_instance_variables, :instance_reader => false
+ self.protected_instance_variables = []
+ end
+
# Overwrite process to setup I18n proxy.
def process(*) #:nodoc:
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
@@ -53,14 +57,20 @@ module AbstractController
end
end
- attr_writer :view_context_class
+ attr_internal_writer :view_context_class
+
+ # Explicitly define protected_instance_variables so it can be
+ # inherited and overwritten by other modules if needed.
+ def protected_instance_variables
+ config.protected_instance_variables
+ end
def view_context_class
- @view_context_class || self.class.view_context_class
+ @_view_context_class || self.class.view_context_class
end
def initialize(*)
- @view_context_class = nil
+ @_view_context_class = nil
super
end
@@ -79,7 +89,7 @@ module AbstractController
# Returns an object that is able to render templates.
def view_renderer
- @view_renderer ||= ActionView::Renderer.new(lookup_context)
+ @_view_renderer ||= ActionView::Renderer.new(lookup_context)
end
# Normalize arguments, options and then delegates render_to_body and
@@ -112,13 +122,19 @@ module AbstractController
private
+ DEFAULT_PROTECTED_INSTANCE_VARIABLES = %w(
+ @_action_name @_response_body @_formats @_prefixes @_config
+ @_view_context_class @_view_renderer @_lookup_context
+ )
+
# This method should return a hash with assigns.
# You can overwrite this configuration per controller.
# :api: public
def view_assigns
hash = {}
variables = instance_variable_names
- variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
+ variables -= protected_instance_variables
+ variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES
variables.each { |name| hash[name.to_s[1, name.length]] = instance_variable_get(name) }
hash
end
diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb
index 0893459e24..6b7aae8c74 100644
--- a/actionpack/lib/abstract_controller/view_paths.rb
+++ b/actionpack/lib/abstract_controller/view_paths.rb
@@ -39,7 +39,7 @@ module AbstractController
# templates, i.e. view paths and details. Check ActionView::LookupContext for more
# information.
def lookup_context
- @lookup_context ||=
+ @_lookup_context ||=
ActionView::LookupContext.new(self.class._view_paths, details_for_lookup, _prefixes)
end
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index 3fae697cc3..8d813a8e38 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -7,8 +7,10 @@ module ActionController
def start_processing(event)
payload = event.payload
params = payload[:params].except(*INTERNAL_PARAMS)
+ format = payload[:format]
+ format = format.to_s.upcase if format.is_a?(Symbol)
- info " Processing by #{payload[:controller]}##{payload[:action]} as #{payload[:formats].first.to_s.upcase}"
+ info " Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
info " Parameters: #{params.inspect}" unless params.empty?
end
diff --git a/actionpack/lib/action_controller/metal/compatibility.rb b/actionpack/lib/action_controller/metal/compatibility.rb
index 006b9fd456..05dca445a4 100644
--- a/actionpack/lib/action_controller/metal/compatibility.rb
+++ b/actionpack/lib/action_controller/metal/compatibility.rb
@@ -18,13 +18,10 @@ module ActionController
delegate :default_charset=, :to => "ActionDispatch::Response"
end
- # TODO: Update protected instance variables list
- config_accessor :protected_instance_variables
- self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render
- @variables_added @request_origin @url
- @parent_controller @action_name
- @before_filter_chain_aborted @_headers @_params
- @_response)
+ self.protected_instance_variables = %w(
+ @_status @_headers @_params @_env @_response @_request
+ @_view_runtime @_stream @_url_options @_action_has_layout
+ )
def rescue_action(env)
raise env["action_dispatch.rescue.exception"]
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
index 3ec0c4c6a4..e8e465d3ba 100644
--- a/actionpack/lib/action_controller/metal/implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -1,21 +1,19 @@
module ActionController
module ImplicitRender
def send_action(method, *args)
- if respond_to?(method, true)
- ret = super
- default_render unless response_body
- ret
- else
- default_render
- end
+ ret = super
+ default_render unless response_body
+ ret
end
def default_render(*args)
render(*args)
end
- def action_method?(action_name)
- super || template_exists?(action_name.to_s, _prefixes)
+ def method_for_action(action_name)
+ super || if template_exists?(action_name.to_s, _prefixes)
+ "default_render"
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index 4e54c2ad88..16cbbce2fb 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -19,7 +19,7 @@ module ActionController
:controller => self.class.name,
:action => self.action_name,
:params => request.filtered_parameters,
- :formats => request.formats.map(&:to_sym),
+ :format => request.format.ref,
:method => request.method,
:path => (request.fullpath rescue "unknown")
}
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index 21bbe17dc3..9b27bb8b91 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -125,7 +125,7 @@ module ActionController
# module is inherited.
def inherited(klass)
if klass._wrapper_options[:format].present?
- klass._set_wrapper_defaults(klass._wrapper_options)
+ klass._set_wrapper_defaults(klass._wrapper_options.slice(:format))
end
super
end
@@ -136,15 +136,23 @@ module ActionController
# 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
+ #
+ # This method also does namespace lookup. Foo::Bar::UsersController will
+ # try to find Foo::Bar::User, Foo::User and finally User.
+ def _default_wrap_model #:nodoc:
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
+ rescue NameError, ArgumentError => e
+ if e.message =~ /is not missing constant|uninitialized constant #{model_name}/
+ namespaces = model_name.split("::")
+ namespaces.delete_at(-2)
+ break if namespaces.last == model_name
+ model_name = namespaces.join("::")
+ else
+ raise
+ end
end until model_klass
model_klass
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 1cd93a188c..13044a7450 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -73,7 +73,10 @@ module ActionController #:nodoc:
protected
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
- verified_request? || handle_unverified_request
+ unless verified_request?
+ logger.debug "WARNING: Can't verify CSRF token authenticity" if logger
+ handle_unverified_request
+ end
end
def handle_unverified_request
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/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index 09dd08898c..91a97c02ff 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -33,7 +33,7 @@ module HTML
result = super
# strip any comments, and if they have a newline at the end (ie. line with
# only a comment) strip that too
- result.gsub!(/<!--(.*?)-->[\n]?/m, "") if result
+ result = result.gsub(/<!--(.*?)-->[\n]?/m, "") if (result && result =~ /<!--(.*?)-->[\n]?/m)
# Recurse - handle all dirty nested tags
result == text ? result : sanitize(result, options)
end
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index 4f4cb96a74..aaed0d750f 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -42,20 +42,6 @@ module ActionDispatch
attr_reader :cache_control, :etag
alias :etag? :etag
- def initialize(*)
- super
-
- @cache_control = {}
- @etag = self["ETag"]
-
- if cache_control = self["Cache-Control"]
- cache_control.split(/,\s*/).each do |segment|
- first, last = segment.split("=")
- @cache_control[first.to_sym] = last || true
- end
- end
- end
-
def last_modified
if last = headers['Last-Modified']
Time.httpdate(last)
@@ -77,6 +63,18 @@ module ActionDispatch
private
+ def prepare_cache_control!
+ @cache_control = {}
+ @etag = self["ETag"]
+
+ if cache_control = self["Cache-Control"]
+ cache_control.split(/,\s*/).each do |segment|
+ first, last = segment.split("=")
+ @cache_control[first.to_sym] = last || true
+ end
+ end
+ end
+
def handle_conditional_get!
if etag? || last_modified? || !@cache_control.empty?
set_conditional_cache_control!
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/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 1f4f3ac0da..3a6b1da4fd 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -56,26 +56,25 @@ module ActionDispatch # :nodoc:
cattr_accessor(:default_charset) { "utf-8" }
- module Setup
- def initialize(status = 200, header = {}, body = [])
- self.body, self.header, self.status = body, header, status
+ include Rack::Response::Helpers
+ include ActionDispatch::Http::Cache::Response
- @sending_file = false
- @blank = false
+ def initialize(status = 200, header = {}, body = [])
+ self.body, self.header, self.status = body, header, status
- if content_type = self["Content-Type"]
- type, charset = content_type.split(/;\s*charset=/)
- @content_type = Mime::Type.lookup(type)
- @charset = charset || "UTF-8"
- end
+ @sending_file = false
+ @blank = false
- yield self if block_given?
+ if content_type = self["Content-Type"]
+ type, charset = content_type.split(/;\s*charset=/)
+ @content_type = Mime::Type.lookup(type)
+ @charset = charset || "UTF-8"
end
- end
- include Rack::Response::Helpers
- include Setup
- include ActionDispatch::Http::Cache::Response
+ prepare_cache_control!
+
+ yield self if block_given?
+ end
def status=(status)
@status = Rack::Utils.status_code(status)
@@ -116,9 +115,32 @@ module ActionDispatch # :nodoc:
EMPTY = " "
+ class BodyBuster #:nodoc:
+ def initialize(response)
+ @response = response
+ @body = ""
+ end
+
+ def bust(body)
+ body.call(@response, self)
+ body.close if body.respond_to?(:close)
+ @body
+ end
+
+ def write(string)
+ @body << string.to_s
+ end
+ end
+
def body=(body)
@blank = true if body == EMPTY
+ if body.respond_to?(:call)
+ ActiveSupport::Deprecation.warn "Setting a Proc or an object that responds to call " \
+ "in response_body is no longer supported", caller
+ body = BodyBuster.new(self).bust(body)
+ end
+
# Explicitly check for strings. This is *wrong* theoretically
# but if we don't check this, the performance on string bodies
# is bad on Ruby 1.8 (because strings responds to each then).
@@ -150,6 +172,10 @@ module ActionDispatch # :nodoc:
headers['Location'] = url
end
+ def close
+ @body.close if @body.respond_to?(:close)
+ end
+
def to_a
assign_default_content_type_and_charset!
handle_conditional_get!
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/diagnostics.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb
index 2099fd069a..4b9d3141d5 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb
@@ -1,7 +1,7 @@
<h1>
<%=h @exception.class.to_s %>
<% if @request.parameters['controller'] %>
- in <%=h @request.parameters['controller'].classify.pluralize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
+ in <%=h @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
<% end %>
</h1>
<pre><%=h @exception.message %></pre>
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 97e8ccc9a5..5097f6732d 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -224,6 +224,7 @@ module ActionDispatch
self.valid_conditions.push(:controller, :action)
@append = []
+ @prepend = []
@disable_clear_and_finalize = false
clear!
end
@@ -232,7 +233,6 @@ module ActionDispatch
clear! unless @disable_clear_and_finalize
eval_block(block)
finalize! unless @disable_clear_and_finalize
-
nil
end
@@ -240,6 +240,10 @@ module ActionDispatch
@append << block
end
+ def prepend(&block)
+ @prepend << block
+ 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. " <<
@@ -262,8 +266,6 @@ module ActionDispatch
end
def clear!
- # Clear the controller cache so we may discover new ones
- @controller_constraints = nil
@finalized = false
routes.clear
named_routes.clear
@@ -271,6 +273,7 @@ module ActionDispatch
:parameters_key => PARAMETERS_KEY,
:request_class => request_class
)
+ @prepend.each { |blk| eval_block(blk) }
end
def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
index d430691429..397bda41d5 100644
--- a/actionpack/lib/action_dispatch/testing/test_process.rb
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -29,7 +29,7 @@ module ActionDispatch
@response.redirect_url
end
- # Shortcut for <tt>ARack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
+ # Shortcut for <tt>Rack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
#
# post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
#
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.rb b/actionpack/lib/action_view.rb
index 92b6f7c770..a67b61c1ef 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -50,6 +50,7 @@ module ActionView
autoload :Resolver
autoload :PathResolver
autoload :FileSystemResolver
+ autoload :OptimizedFileSystemResolver
autoload :FallbackFileSystemResolver
end
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index ead7feb091..3b5f4e694f 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -135,8 +135,12 @@ module ActionView
# for elements that will be fragment cached.
def content_for(name, content = nil, &block)
content = capture(&block) if block_given?
- result = @view_flow.append(name, content) if content
- result unless content
+ if content
+ @view_flow.append(name, content)
+ nil
+ else
+ @view_flow.get(name)
+ end
end
# The same as +content_for+ but when used with streaming flushes
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 326ad40c8d..853ab061d2 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -94,9 +94,20 @@ module ActionView
when 43200..86399 then locale.t :about_x_months, :count => 1
when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
else
- distance_in_years = distance_in_minutes / 525600
- minute_offset_for_leap_year = (distance_in_years / 4) * 1440
- remainder = ((distance_in_minutes - minute_offset_for_leap_year) % 525600)
+ fyear = from_time.year
+ fyear += 1 if from_time.month >= 3
+ tyear = to_time.year
+ tyear -= 1 if to_time.month < 3
+ leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)}
+ minute_offset_for_leap_year = leap_years * 1440
+ # Discount the leap year days when calculating year distance.
+ # e.g. if there are 20 leap year days between 2 dates having the same day
+ # and month then the based on 365 days calculation
+ # the distance in years will come out to over 80 years when in written
+ # english it would read better as about 80 years.
+ minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
+ remainder = (minutes_with_offset % 525600)
+ distance_in_years = (minutes_with_offset / 525600)
if remainder < 131400
locale.t(:about_x_years, :count => distance_in_years)
elsif remainder < 394200
@@ -207,7 +218,8 @@ module ActionView
# Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a
# specified time-based attribute (identified by +method+) on an object assigned to the template (identified by
- # +object+). You can include the seconds with <tt>:include_seconds</tt>.
+ # +object+). You can include the seconds with <tt>:include_seconds</tt>. You can get hours in the AM/PM format
+ # with <tt>:ampm</tt> option.
#
# This method will also generate 3 input hidden tags, for the actual year, month and day unless the option
# <tt>:ignore_date</tt> is set to +true+. If you set the <tt>:ignore_date</tt> to +true+, you must have a
@@ -231,6 +243,9 @@ module ActionView
# time_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours
# time_select("post", "written_on", :prompt => true) # generic prompts for all
#
+ # # You can set :ampm option to true which will show the hours as: 12 PM, 01 AM .. 11 PM.
+ # time_select 'game', 'game_time', {:ampm => true}
+ #
# The selects are prepared for multi-parameter assignment to an Active Record object.
#
# Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
@@ -258,6 +273,9 @@ module ActionView
# # be stored in the trip variable in the departing attribute.
# datetime_select("trip", "departing", :default => 3.days.from_now)
#
+ # # Generate a datetime select with hours in the AM/PM format
+ # datetime_select("post", "written_on", :ampm => true)
+ #
# # Generates a datetime select that discards the type that, when POSTed, will be stored in the post variable
# # as the written_on attribute.
# datetime_select("post", "written_on", :discard_type => true)
@@ -307,6 +325,9 @@ module ActionView
# # my_date_time (four days after today)
# select_datetime(my_date_time, :discard_type => true)
#
+ # # Generate a datetime field with hours in the AM/PM format
+ # select_datetime(my_date_time, :ampm => true)
+ #
# # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
# # prefixed with 'payday' rather than 'date'
# select_datetime(my_date_time, :prefix => 'payday')
@@ -388,7 +409,10 @@ module ActionView
# # separated by ':' and includes an input for seconds.
# select_time(my_time, :time_separator => ':', :include_seconds => true)
#
- # # Generates a time select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
+ # # Generate a time select field with hours in the AM/PM format
+ # select_time(my_time, :ampm => true)
+ #
+ # # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts.
# select_time(my_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
# select_time(my_time, :prompt => {:hour => true}) # generic prompt for hours
# select_time(my_time, :prompt => true) # generic prompts for all
@@ -469,6 +493,9 @@ module ActionView
# # generic prompt.
# select_hour(13, :prompt => 'Choose hour')
#
+ # # Generate a select field for hours in the AM/PM format
+ # select_hour(my_time, :ampm => true)
+ #
def select_hour(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_hour
end
@@ -602,6 +629,15 @@ module ActionView
:year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6
}.freeze
+ AMPM_TRANSLATION = Hash[
+ [[0, "12 AM"], [1, "01 AM"], [2, "02 AM"], [3, "03 AM"],
+ [4, "04 AM"], [5, "05 AM"], [6, "06 AM"], [7, "07 AM"],
+ [8, "08 AM"], [9, "09 AM"], [10, "10 AM"], [11, "11 AM"],
+ [12, "12 PM"], [13, "01 PM"], [14, "02 PM"], [15, "03 PM"],
+ [16, "04 PM"], [17, "05 PM"], [18, "06 PM"], [19, "07 PM"],
+ [20, "08 PM"], [21, "09 PM"], [22, "10 PM"], [23, "11 PM"]]
+ ].freeze
+
def initialize(datetime, options = {}, html_options = {})
@options = options.dup
@html_options = html_options.dup
@@ -693,7 +729,7 @@ module ActionView
if @options[:use_hidden] || @options[:discard_hour]
build_hidden(:hour, hour)
else
- build_options_and_select(:hour, hour, :end => 23)
+ build_options_and_select(:hour, hour, :end => 23, :ampm => @options[:ampm])
end
end
@@ -817,7 +853,7 @@ module ActionView
start = options.delete(:start) || 0
stop = options.delete(:end) || 59
step = options.delete(:step) || 1
- options.reverse_merge!({:leading_zeros => true})
+ options.reverse_merge!({:leading_zeros => true, :ampm => false})
leading_zeros = options.delete(:leading_zeros)
select_options = []
@@ -825,7 +861,8 @@ module ActionView
value = leading_zeros ? sprintf("%02d", i) : i
tag_options = { :value => value }
tag_options[:selected] = "selected" if selected == i
- select_options << content_tag(:option, value, tag_options)
+ text = options[:ampm] ? AMPM_TRANSLATION[i] : value
+ select_options << content_tag(:option, text, tag_options)
end
(select_options.join("\n") + "\n").html_safe
end
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 06975ffa2f..f0ed3425de 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -167,12 +167,12 @@ module ActionView
@frozen_formats = true
end
- # Overload formats= to reject ["*/*"] values.
+ # Overload formats= to expand ["*/*"] values and automatically
+ # add :html as fallback to :js.
def formats=(values)
- if values && values.size == 1
- value = values.first
- values = nil if value == "*/*"
- values << :html if value == :js
+ if values
+ values.concat(_formats_defaults) if values.delete "*/*"
+ values << :html if values == [:js]
end
super(values)
end
diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb
index 8b840a6463..e0cb5d6a70 100644
--- a/actionpack/lib/action_view/path_set.rb
+++ b/actionpack/lib/action_view/path_set.rb
@@ -35,7 +35,7 @@ module ActionView #:nodoc:
each_with_index do |path, i|
path = path.to_s if path.is_a?(Pathname)
next unless path.is_a?(String)
- self[i] = FileSystemResolver.new(path)
+ self[i] = OptimizedFileSystemResolver.new(path)
end
end
end
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index e246646963..d4448a7b33 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -1,3 +1,4 @@
+require "active_support/core_ext/array/wrap"
require "active_support/core_ext/enumerable"
module ActionView
@@ -29,6 +30,7 @@ module ActionView
def initialize(paths, path, prefixes, partial, details, *)
@path = path
+ prefixes = Array.wrap(prefixes)
display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ")
template_type = if partial
"partial"
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 870897958a..2b9427ace5 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -10,17 +10,16 @@ module ActionView
attr_reader :name, :prefix, :partial, :virtual
alias_method :partial?, :partial
- def initialize(name, prefix, partial)
- @name, @prefix, @partial = name, prefix, partial
- rebuild(@name, @prefix, @partial)
+ def self.build(name, prefix, partial)
+ virtual = ""
+ virtual << "#{prefix}/" unless prefix.empty?
+ virtual << (partial ? "_#{name}" : name)
+ new name, prefix, partial, virtual
end
- def rebuild(name, prefix, partial)
- @virtual = ""
- @virtual << "#{prefix}/" unless prefix.empty?
- @virtual << (partial ? "_#{name}" : name)
-
- self.replace(@virtual)
+ def initialize(name, prefix, partial, virtual)
+ @name, @prefix, @partial = name, prefix, partial
+ super(virtual)
end
end
@@ -60,7 +59,7 @@ module ActionView
# Helpers that builds a path. Useful for building virtual paths.
def build_path(name, prefix, partial)
- Path.new(name, prefix, partial)
+ Path.build(name, prefix, partial)
end
# Handles templates caching. If a key is given and caching is on
@@ -112,7 +111,8 @@ module ActionView
end
end
- class PathResolver < Resolver
+ # An abstract class that implements a Resolver with path semantics.
+ class PathResolver < Resolver #:nodoc:
EXTENSIONS = [:locale, :formats, :handlers]
DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}"
@@ -124,13 +124,12 @@ module ActionView
private
def find_templates(name, prefix, partial, details)
- path = build_path(name, prefix, partial)
- extensions = Hash[EXTENSIONS.map { |ext| [ext, details[ext]] }.flatten(0)]
- query(path, extensions, details[:formats])
+ path = Path.build(name, prefix, partial)
+ query(path, details, details[:formats])
end
- def query(path, exts, formats)
- query = build_query(path, exts)
+ def query(path, details, formats)
+ query = build_query(path, details)
templates = []
sanitizer = Hash.new { |h,k| h[k] = Dir["#{File.dirname(k)}/*"] }
@@ -138,7 +137,7 @@ module ActionView
next if File.directory?(p) || !sanitizer[p].include?(p)
handler, format = extract_handler_and_format(p, formats)
- contents = File.open(p, "rb") {|io| io.read }
+ contents = File.open(p, "rb") { |io| io.read }
templates << Template.new(contents, File.expand_path(p), handler,
:virtual_path => path.virtual, :format => format, :updated_at => mtime(p))
@@ -147,18 +146,15 @@ module ActionView
templates
end
- # Helper for building query glob string based on resolver's pattern.
- def build_query(path, exts)
+ # Helper for building query glob string based on resolver's pattern.
+ def build_query(path, details)
query = @pattern.dup
query.gsub!(/\:prefix(\/)?/, path.prefix.empty? ? "" : "#{path.prefix}\\1") # prefix can be empty...
query.gsub!(/\:action/, path.partial? ? "_#{path.name}" : path.name)
- exts.each { |ext, variants|
+ details.each do |ext, variants|
query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}")
- }
-
- query.gsub!('.{html,', '.{html,text.html,')
- query.gsub!('.{text,', '.{text,text.plain,')
+ end
File.expand_path(query, @path)
end
@@ -235,9 +231,25 @@ module ActionView
alias :== :eql?
end
+ # An Optimized resolver for Rails' most common case.
+ class OptimizedFileSystemResolver < FileSystemResolver #:nodoc:
+ def build_query(path, details)
+ exts = EXTENSIONS.map { |ext| details[ext] }
+ query = File.join(@path, path)
+
+ exts.each do |ext|
+ query << "{"
+ ext.compact.each { |e| query << ".#{e}," }
+ query << "}"
+ end
+
+ query
+ end
+ end
+
# The same as FileSystemResolver but does not allow templates to store
# a virtual path since it is invalid for such resolvers.
- class FallbackFileSystemResolver < FileSystemResolver
+ class FallbackFileSystemResolver < FileSystemResolver #:nodoc:
def self.instances
[new(""), new("/")]
end
diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb
index 9c10decd60..c75b7d4de0 100644
--- a/actionpack/lib/sprockets/railtie.rb
+++ b/actionpack/lib/sprockets/railtie.rb
@@ -34,12 +34,20 @@ module Sprockets
app.assets = asset_environment(app)
ActiveSupport.on_load(:action_view) do
- app.assets.context.instance_eval do
+ if app.assets.respond_to?(:context_class)
+ context = app.assets.context_class
+
+ # TODO: Remove this condition when Sprockets 2.0.beta.3 is released
+ else
+ context = app.assets.context
+ end
+
+ context.instance_eval do
include ::ActionView::Helpers::SprocketsHelper
end
end
- app.routes.append do
+ app.routes.prepend do
mount app.assets => assets.prefix
end