aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
authorAlvaro Pereyra <alvaro@xendacentral.com>2012-05-28 02:29:46 -0500
committerAlvaro Pereyra <alvaro@xendacentral.com>2012-05-28 02:29:46 -0500
commit72973a30704894c808836d80a001208c1af39e7c (patch)
treeab84954fed3e67628bb0884b0e4b0376638bc5dc /actionpack/lib
parent011863673a353c334ddb2c93227dceadc5d7c3b6 (diff)
parent0ad2146ccf45b3a26924e729a92cd2ff98356413 (diff)
downloadrails-72973a30704894c808836d80a001208c1af39e7c.tar.gz
rails-72973a30704894c808836d80a001208c1af39e7c.tar.bz2
rails-72973a30704894c808836d80a001208c1af39e7c.zip
Merge branch 'master' of github.com:lifo/docrails
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller/base.rb2
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb1
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb3
-rw-r--r--actionpack/lib/action_controller/base.rb1
-rw-r--r--actionpack/lib/action_controller/caching/actions.rb5
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb4
-rw-r--r--actionpack/lib/action_controller/metal.rb2
-rw-r--r--actionpack/lib/action_controller/metal/exceptions.rb5
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb1
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb1
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb3
-rw-r--r--actionpack/lib/action_controller/metal/responder.rb10
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb13
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb3
-rw-r--r--actionpack/lib/action_dispatch/middleware/reloader.rb1
-rw-r--r--actionpack/lib/action_dispatch/request/session.rb8
-rw-r--r--actionpack/lib/action_dispatch/routing.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb7
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/redirection.rb10
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb20
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/response.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb21
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb7
-rw-r--r--actionpack/lib/action_dispatch/testing/test_request.rb2
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb1
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb90
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb55
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/output_safety_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/record_tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/rendering_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/sanitize_helper.rb12
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/tags.rb5
-rw-r--r--actionpack/lib/action_view/helpers/tags/color_field.rb25
-rw-r--r--actionpack/lib/action_view/helpers/tags/date_field.rb13
-rw-r--r--actionpack/lib/action_view/helpers/tags/datetime_field.rb22
-rw-r--r--actionpack/lib/action_view/helpers/tags/datetime_local_field.rb19
-rw-r--r--actionpack/lib/action_view/helpers/tags/month_field.rb13
-rw-r--r--actionpack/lib/action_view/helpers/tags/select.rb1
-rw-r--r--actionpack/lib/action_view/helpers/tags/time_field.rb13
-rw-r--r--actionpack/lib/action_view/helpers/tags/week_field.rb13
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb34
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb1
-rw-r--r--actionpack/lib/action_view/template.rb32
-rw-r--r--actionpack/lib/action_view/template/resolver.rb1
53 files changed, 432 insertions, 72 deletions
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index 32ec7ced0f..9c3960961b 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -141,7 +141,7 @@ module AbstractController
#
# 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
+ # this method considers actions that are also available
# through other means, for example, implicit render ones.
#
# ==== Parameters
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index 529f920e6c..4e0672d590 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -90,6 +90,7 @@ module AbstractController
# +symbols+, +strings+, +modules+ and blocks.
#
# helper(:three, BlindHelper) { def mice() 'mice' end }
+ #
def helper(*args, &block)
modules_for_helpers(args).each do |mod|
add_template_helper(mod)
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index bc9f6fc3e8..c1b3994035 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -203,8 +203,7 @@ module AbstractController
include Rendering
included do
- class_attribute :_layout, :_layout_conditions,
- :instance_reader => false, :instance_writer => false
+ class_attribute :_layout, :_layout_conditions, :instance_accessor => false
self._layout = nil
self._layout_conditions = {}
_write_layout_method
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 90058245f5..71425cd542 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -167,6 +167,7 @@ module ActionController
# redirect_to(:action => "elsewhere") and return if monkeys.nil?
# render :action => "overthere" # won't be called if monkeys is nil
# end
+ #
class Base < Metal
abstract!
diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb
index 80901b8bf3..0238135bc1 100644
--- a/actionpack/lib/action_controller/caching/actions.rb
+++ b/actionpack/lib/action_controller/caching/actions.rb
@@ -47,7 +47,7 @@ module ActionController #:nodoc:
# And you can also use <tt>:if</tt> (or <tt>:unless</tt>) to pass a
# proc that specifies when the action should be cached.
#
- # As of Rails 3.0, you can also pass <tt>:expires_in</tt> with a time
+ # As of Rails 3.0, you can also pass <tt>:expires_in</tt> with a time
# interval (in seconds) to schedule expiration of the cached item.
#
# The following example depicts some of the points made above:
@@ -178,8 +178,9 @@ module ActionController #:nodoc:
private
def normalize!(path)
+ ext = URI.parser.escape(extension) if extension
path << 'index' if path[-1] == ?/
- path << ".#{extension}" if extension and !path.split('?', 2).first.ends_with?(".#{extension}")
+ path << ".#{ext}" if extension and !path.split('?', 2).first.ends_with?(".#{ext}")
URI.parser.unescape(path)
end
end
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index 11aa393bf9..0fb419f941 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -33,9 +33,7 @@ module ActionController
end
def send_file(event)
- message = "Sent file %s"
- message << " (%.1fms)"
- info(message % [event.payload[:path], event.duration])
+ info("Sent file %s (%.1fms)" % [event.payload[:path], event.duration])
end
def redirect_to(event)
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 720c0f2258..92433ab462 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -9,6 +9,7 @@ module ActionController
# class PostsController < ApplicationController
# use AuthenticationMiddleware, :except => [:index, :show]
# end
+ #
class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc:
class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc:
def initialize(klass, *args, &block)
@@ -96,6 +97,7 @@ module ActionController
#
# You can refer to the modules included in <tt>ActionController::Base</tt> to see
# other features you can bring into your metal controller.
+ #
class Metal < AbstractController::Base
abstract!
diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb
index 90648c37ad..8fd8f4797c 100644
--- a/actionpack/lib/action_controller/metal/exceptions.rb
+++ b/actionpack/lib/action_controller/metal/exceptions.rb
@@ -2,6 +2,9 @@ module ActionController
class ActionControllerError < StandardError #:nodoc:
end
+ class BadRequest < ActionControllerError #:nodoc:
+ end
+
class RenderError < ActionControllerError #:nodoc:
end
@@ -38,7 +41,7 @@ module ActionController
class UnknownHttpMethod < ActionControllerError #:nodoc:
end
-
+
class UnknownFormat < ActionControllerError #:nodoc:
end
end
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index 598bc6c5cb..86d061e3b7 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -47,6 +47,7 @@ module ActionController
#
# 23 Aug 11:30 | Carolina Railhawks Soccer Match
# N/A | Carolina Railhaws Training Workshop
+ #
module Helpers
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index d9fc777250..0b800c3c62 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -52,6 +52,7 @@ module ActionController #:nodoc:
end
# Clear all mime types in <tt>respond_to</tt>.
+ #
def clear_respond_to
self.mimes_for_respond_to = Hash.new.freeze
end
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index 1f52c164de..aa67fa7f23 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -193,7 +193,8 @@ module ActionController
def process_action(*args)
if _wrapper_enabled?
wrapped_hash = _wrap_parameters request.request_parameters
- wrapped_filtered_hash = _wrap_parameters request.filtered_parameters
+ wrapped_keys = request.request_parameters.keys
+ wrapped_filtered_hash = _wrap_parameters request.filtered_parameters.slice(*wrapped_keys)
# This will make the wrapped hash accessible from controller and view
request.parameters.merge! wrapped_hash
diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb
index 5aa3b2ca15..83407846dc 100644
--- a/actionpack/lib/action_controller/metal/responder.rb
+++ b/actionpack/lib/action_controller/metal/responder.rb
@@ -142,11 +142,13 @@ module ActionController #:nodoc:
# Initializes a new responder an invoke the proper format. If the format is
# not defined, call to_format.
+ #
def self.call(*args)
new(*args).respond
end
# Main entry point for responder responsible to dispatch to the proper format.
+ #
def respond
method = "to_#{format}"
respond_to?(method) ? send(method) : to_format
@@ -154,6 +156,7 @@ module ActionController #:nodoc:
# HTML format does not render the resource, it always attempt to render a
# template.
+ #
def to_html
default_render
rescue ActionView::MissingTemplate => e
@@ -168,6 +171,7 @@ module ActionController #:nodoc:
# All other formats follow the procedure below. First we try to render a
# template, if the template is not available, we verify if the resource
# responds to :to_format and display it.
+ #
def to_format
if get? || !has_errors? || response_overridden?
default_render
@@ -205,12 +209,14 @@ module ActionController #:nodoc:
end
# Checks whether the resource responds to the current format or not.
+ #
def resourceful?
resource.respond_to?("to_#{format}")
end
# Returns the resource location by retrieving it from the options or
# returning the resources array.
+ #
def resource_location
options[:location] || resources
end
@@ -219,6 +225,7 @@ module ActionController #:nodoc:
# If a response block was given, use it, otherwise call render on
# controller.
+ #
def default_render
if @default_response
@default_response.call(options)
@@ -243,6 +250,7 @@ module ActionController #:nodoc:
# Results in:
#
# render :xml => @user, :status => :created
+ #
def display(resource, given_options={})
controller.render given_options.merge!(options).merge!(format => resource)
end
@@ -252,12 +260,14 @@ module ActionController #:nodoc:
end
# Check whether the resource has errors.
+ #
def has_errors?
resource.respond_to?(:errors) && !resource.errors.empty?
end
# By default, render the <code>:edit</code> action for HTML requests with errors, unless
# the verb was POST.
+ #
def default_action
@action ||= DEFAULT_ACTIONS_FOR_VERBS[request.request_method_symbol]
end
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 0c3caa9514..eeb37db2e7 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -194,6 +194,7 @@ module ActionController #:nodoc:
# ==== Passenger
#
# To be described.
+ #
module Streaming
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index ca40ab9502..e31f3b823d 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -46,6 +46,7 @@ module ActionDispatch
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first
+ #
def format(view_path = [])
formats.first
end
@@ -81,6 +82,7 @@ module ActionDispatch
# Receives an array of mimes and return the first user sent mime that
# matches the order array.
+ #
def negotiate_mime(order)
formats.each do |priority|
if priority == Mime::ALL
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 56908b5794..aa5ba3e8a5 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -231,17 +231,24 @@ module ActionDispatch
# Override Rack's GET method to support indifferent access
def GET
- @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {})
+ begin
+ @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {})
+ rescue TypeError => e
+ raise ActionController::BadRequest, "Invalid query parameters: #{e.message}"
+ end
end
alias :query_parameters :GET
# Override Rack's POST method to support indifferent access
def POST
- @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {})
+ begin
+ @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {})
+ rescue TypeError => e
+ raise ActionController::BadRequest, "Invalid request parameters: #{e.message}"
+ end
end
alias :request_parameters :POST
-
# Returns the authorization header regardless of whether it was specified directly or through one of the
# proxy alternatives.
def authorization
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index a8f49bd3bd..7349b578d2 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -12,7 +12,8 @@ module ActionDispatch
'ActionController::MethodNotAllowed' => :method_not_allowed,
'ActionController::NotImplemented' => :not_implemented,
'ActionController::UnknownFormat' => :not_acceptable,
- 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
+ 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
+ 'ActionController::BadRequest' => :bad_request
)
cattr_accessor :rescue_templates
diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb
index 23415dae54..2f6968eb2e 100644
--- a/actionpack/lib/action_dispatch/middleware/reloader.rb
+++ b/actionpack/lib/action_dispatch/middleware/reloader.rb
@@ -22,6 +22,7 @@ module ActionDispatch
# is false. Callbacks may be registered even when it is not included in the
# middleware stack, but are executed only when <tt>ActionDispatch::Reloader.prepare!</tt>
# or <tt>ActionDispatch::Reloader.cleanup!</tt> are called manually.
+ #
class Reloader
include ActiveSupport::Callbacks
diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb
index 4ad7071820..d8bcc28613 100644
--- a/actionpack/lib/action_dispatch/request/session.rb
+++ b/actionpack/lib/action_dispatch/request/session.rb
@@ -87,6 +87,14 @@ module ActionDispatch
alias :key? :has_key?
alias :include? :has_key?
+ def keys
+ @delegate.keys
+ end
+
+ def values
+ @delegate.values
+ end
+
def []=(key, value)
load_for_write!
@delegate[key.to_s] = value
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index a2a6fb39dc..38a0270151 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -277,6 +277,7 @@ module ActionDispatch
# rake routes
#
# Target specific controllers by prefixing the command with <tt>CONTROLLER=x</tt>.
+ #
module Routing
autoload :Mapper, 'action_dispatch/routing/mapper'
autoload :RouteSet, 'action_dispatch/routing/route_set'
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 79eee21619..e43e897783 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -897,6 +897,7 @@ module ActionDispatch
# resources :articles, :id => /[^\/]+/
#
# This allows any character other than a slash as part of your +:id+.
+ #
module Resources
# CANONICAL_ACTIONS holds all actions that does not need a prefix or
# a path appended since they fit properly in their scope level.
@@ -1317,7 +1318,7 @@ module ActionDispatch
def draw(name)
path = @draw_paths.find do |_path|
- _path.join("#{name}.rb").file?
+ File.exists? "#{_path}/#{name}.rb"
end
unless path
@@ -1327,8 +1328,8 @@ module ActionDispatch
raise ArgumentError, msg
end
- route_path = path.join("#{name}.rb")
- instance_eval(route_path.read, route_path.to_s)
+ route_path = "#{path}/#{name}.rb"
+ instance_eval(File.read(route_path), route_path.to_s)
end
# match 'path' => 'controller#action'
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index 817cdb2d4e..8fde667108 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -51,6 +51,7 @@ module ActionDispatch
#
# polymorphic_url([blog, @post]) # calls blog.post_path(@post)
# form_for([blog, @post]) # => "/blog/posts/1"
+ #
module PolymorphicRoutes
# Constructs a call to a named RESTful route for the given record and returns the
# resulting URL string. For example:
@@ -83,6 +84,7 @@ module ActionDispatch
#
# # the class of a record will also map to the collection
# polymorphic_url(Comment) # same as comments_url()
+ #
def polymorphic_url(record_or_hash_or_array, options = {})
if record_or_hash_or_array.kind_of?(Array)
record_or_hash_or_array = record_or_hash_or_array.compact
diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb
index d8beba4397..205ff44b1c 100644
--- a/actionpack/lib/action_dispatch/routing/redirection.rb
+++ b/actionpack/lib/action_dispatch/routing/redirection.rb
@@ -2,6 +2,7 @@ require 'action_dispatch/http/request'
require 'active_support/core_ext/uri'
require 'active_support/core_ext/array/extract_options'
require 'rack/utils'
+require 'action_controller/metal/exceptions'
module ActionDispatch
module Routing
@@ -16,6 +17,14 @@ module ActionDispatch
def call(env)
req = Request.new(env)
+ # If any of the path parameters has a invalid encoding then
+ # raise since it's likely to trigger errors further on.
+ req.symbolized_path_parameters.each do |key, value|
+ unless value.valid_encoding?
+ raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
+ end
+ end
+
uri = URI.parse(path(req.symbolized_path_parameters, req))
uri.scheme ||= req.scheme
uri.host ||= req.host
@@ -121,6 +130,7 @@ module ActionDispatch
# a string.
#
# match 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
+ #
def redirect(*args, &block)
options = args.extract_options!
status = options.delete(:status) || 301
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index c5601a82d6..7872f4007e 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -26,6 +26,15 @@ module ActionDispatch
def call(env)
params = env[PARAMETERS_KEY]
+
+ # If any of the path parameters has a invalid encoding then
+ # raise since it's likely to trigger errors further on.
+ params.each do |key, value|
+ unless value.valid_encoding?
+ raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
+ end
+ end
+
prepare_params!(params)
# Just raise undefined constant errors if a controller was specified as default.
@@ -180,6 +189,7 @@ module ActionDispatch
# Also allow options hash, so you can do:
#
# foo_url(bar, baz, bang, :sort_by => 'baz')
+ #
def define_url_helper(route, name, options)
selector = url_helper_name(name, options[:only_path])
@@ -653,9 +663,13 @@ module ActionDispatch
dispatcher = dispatcher.app
end
- if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false)
- dispatcher.prepare_params!(params)
- return params
+ if dispatcher.is_a?(Dispatcher)
+ if dispatcher.controller(params, false)
+ dispatcher.prepare_params!(params)
+ return params
+ else
+ raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index 207f56aaea..fd3bed7e8f 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -79,6 +79,7 @@ module ActionDispatch
# end
#
# User.find(1).base_uri # => "/users/1"
+ #
module UrlFor
extend ActiveSupport::Concern
include PolymorphicRoutes
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index 3d121b6b9c..b4c8f839ac 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -28,7 +28,7 @@ module ActionDispatch
assert @response.send("#{type}?"), message
else
code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type]
- assert_equal @response.response_code, code, message
+ assert_equal code, @response.response_code, message
end
else
assert_equal type, @response.response_code, message
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 1539b894c9..41fa3a4b95 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -69,11 +69,9 @@ module ActionDispatch
# assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" }
def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
if expected_path =~ %r{://}
- begin
+ fail_on(URI::InvalidURIError) do
uri = URI.parse(expected_path)
expected_path = uri.path.to_s.empty? ? "/" : uri.path
- rescue URI::InvalidURIError => e
- raise ActionController::RoutingError, e.message
end
else
expected_path = "/#{expected_path}" unless expected_path.first == '/'
@@ -140,6 +138,7 @@ module ActionDispatch
# end
# end
# end
+ #
def with_routing
old_routes, @routes = @routes, ActionDispatch::Routing::RouteSet.new
if defined?(@controller) && @controller
@@ -188,14 +187,12 @@ module ActionDispatch
request = ActionController::TestRequest.new
if path =~ %r{://}
- begin
+ fail_on(URI::InvalidURIError) do
uri = URI.parse(path)
request.env["rack.url_scheme"] = uri.scheme || "http"
request.host = uri.host if uri.host
request.port = uri.port if uri.port
request.path = uri.path.to_s.empty? ? "/" : uri.path
- rescue URI::InvalidURIError => e
- raise ActionController::RoutingError, e.message
end
else
path = "/#{path}" unless path.first == "/"
@@ -204,11 +201,21 @@ module ActionDispatch
request.request_method = method if method
- params = @routes.recognize_path(path, { :method => method, :extras => extras })
+ params = fail_on(ActionController::RoutingError) do
+ @routes.recognize_path(path, { :method => method, :extras => extras })
+ end
request.path_parameters = params.with_indifferent_access
request
end
+
+ def fail_on(exception_class)
+ begin
+ yield
+ rescue exception_class => e
+ raise MiniTest::Assertion, e.message
+ end
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 08fd28d72d..3fdc6688c2 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -17,8 +17,8 @@ module ActionDispatch
# a Hash, or a String that is appropriately encoded
# (<tt>application/x-www-form-urlencoded</tt> or
# <tt>multipart/form-data</tt>).
- # - +headers+: Additional HTTP headers to pass, as a Hash. The keys will
- # automatically be upcased, with the prefix 'HTTP_' added if needed.
+ # - +headers+: Additional headers to pass, as a Hash. The headers will be
+ # merged into the Rack env hash.
#
# This method returns an Response object, which one can use to
# inspect the details of the response. Furthermore, if this method was
@@ -73,8 +73,7 @@ module ActionDispatch
#
# The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or
# +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart
- # string; the headers are a hash. Keys are automatically upcased and
- # prefixed with 'HTTP_' if not already.
+ # string; the headers are a hash.
def xml_http_request(request_method, path, parameters = nil, headers = nil)
headers ||= {}
headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb
index d04be2099c..a86b510719 100644
--- a/actionpack/lib/action_dispatch/testing/test_request.rb
+++ b/actionpack/lib/action_dispatch/testing/test_request.rb
@@ -11,7 +11,7 @@ module ActionDispatch
end
def initialize(env = {})
- env = Rails.application.env_config.merge(env) if defined?(Rails.application)
+ env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
super(DEFAULT_ENV.merge(env))
self.host = 'test.host'
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
index d7df9ea0d5..57b0627225 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
@@ -139,6 +139,7 @@ module ActionView
# you have too many stylesheets for IE to load.
#
# stylesheet_link_tag :all, :concat => true
+ #
def stylesheet_link_tag(*sources)
@stylesheet_include ||= StylesheetIncludeTag.new(config, asset_paths)
@stylesheet_include.include_tag(*sources)
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index c1f47a2eac..397738dd98 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -33,6 +33,7 @@ module ActionView
# <body>
# <b><%= @greeting %></b>
# </body></html>
+ #
def capture(*args)
value = nil
buffer = with_output_buffer { value = yield(*args) }
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 61e7a89585..ac150882b1 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -342,7 +342,7 @@ module ActionView
# Example:
#
# <%= form_for(@post) do |f| %>
- # <% f.fields_for(:comments, :include_id => false) do |cf| %>
+ # <%= f.fields_for(:comments, :include_id => false) do |cf| %>
# ...
# <% end %>
# <% end %>
@@ -763,6 +763,7 @@ module ActionView
#
# text_field(:snippet, :code, :size => 20, :class => 'code_input')
# # => <input type="text" id="snippet_code" name="snippet[code]" size="20" value="#{@snippet.code}" class="code_input" />
+ #
def text_field(object_name, method, options = {})
Tags::TextField.new(object_name, method, self, options).render
end
@@ -784,6 +785,7 @@ module ActionView
#
# password_field(:account, :pin, :size => 20, :class => 'form_input')
# # => <input type="password" id="account_pin" name="account[pin]" size="20" class="form_input" />
+ #
def password_field(object_name, method, options = {})
Tags::PasswordField.new(object_name, method, self, options).render
end
@@ -822,6 +824,7 @@ module ActionView
#
# file_field(:attachment, :file, :class => 'file_input')
# # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
+ #
def file_field(object_name, method, options = {})
Tags::FileField.new(object_name, method, self, options).render
end
@@ -910,6 +913,7 @@ module ActionView
# check_box("eula", "accepted", { :class => 'eula_check' }, "yes", "no")
# # => <input name="eula[accepted]" type="hidden" value="no" />
# # <input type="checkbox" class="eula_check" id="eula_accepted" name="eula[accepted]" value="yes" />
+ #
def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
Tags::CheckBox.new(object_name, method, self, checked_value, unchecked_value, options).render
end
@@ -935,6 +939,15 @@ module ActionView
Tags::RadioButton.new(object_name, method, self, tag_value, options).render
end
+ # Returns a text_field of type "color".
+ #
+ # color_field("car", "color")
+ # # => <input id="car_color" name="car[color]" type="color" value="#000000" />
+ #
+ def color_field(object_name, method, options = {})
+ Tags::ColorField.new(object_name, method, self, options).render
+ end
+
# Returns an input of type "search" for accessing a specified attribute (identified by +method+) on an object
# assigned to the template (identified by +object_name+). Inputs of type "search" may be styled differently by
# some browsers.
@@ -962,6 +975,7 @@ module ActionView
#
# telephone_field("user", "phone")
# # => <input id="user_phone" name="user[phone]" type="tel" />
+ #
def telephone_field(object_name, method, options = {})
Tags::TelField.new(object_name, method, self, options).render
end
@@ -980,6 +994,7 @@ module ActionView
# @user.born_on = Date.new(1984, 1, 27)
# date_field("user", "born_on", value: "1984-05-12")
# # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-05-12" />
+ #
def date_field(object_name, method, options = {})
Tags::DateField.new(object_name, method, self, options).render
end
@@ -996,14 +1011,84 @@ module ActionView
# === Example
# time_field("task", "started_at")
# # => <input id="task_started_at" name="task[started_at]" type="time" />
+ #
def time_field(object_name, method, options = {})
Tags::TimeField.new(object_name, method, self, options).render
end
+ # Returns a text_field of type "datetime".
+ #
+ # datetime_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T.%L%z"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 12)
+ # datetime_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime" value="1984-01-12T00:00:00.000+0000" />
+ #
+ def datetime_field(object_name, method, options = {})
+ Tags::DatetimeField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "datetime-local".
+ #
+ # datetime_local_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 12)
+ # datetime_local_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" value="1984-01-12T00:00:00" />
+ #
+ def datetime_local_field(object_name, method, options = {})
+ Tags::DatetimeLocalField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "month".
+ #
+ # month_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="month" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 27)
+ # month_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-01" />
+ #
+ def month_field(object_name, method, options = {})
+ Tags::MonthField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "week".
+ #
+ # week_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="week" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-W%W"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 5, 12)
+ # week_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-W19" />
+ #
+ def week_field(object_name, method, options = {})
+ Tags::WeekField.new(object_name, method, self, options).render
+ end
+
# Returns a text_field of type "url".
#
# url_field("user", "homepage")
# # => <input id="user_homepage" name="user[homepage]" type="url" />
+ #
def url_field(object_name, method, options = {})
Tags::UrlField.new(object_name, method, self, options).render
end
@@ -1012,6 +1097,7 @@ module ActionView
#
# email_field("user", "address")
# # => <input id="user_address" name="user[address]" type="email" />
+ #
def email_field(object_name, method, options = {})
Tags::EmailField.new(object_name, method, self, options).render
end
@@ -1191,6 +1277,7 @@ module ActionView
# submit:
# post:
# create: "Add %{model}"
+ #
def submit(value=nil, options={})
value, options = nil, value if value.is_a?(Hash)
value ||= submit_default_value
@@ -1223,6 +1310,7 @@ module ActionView
# submit:
# post:
# create: "Add %{model}"
+ #
def button(value=nil, options={})
value, options = nil, value if value.is_a?(Hash)
value ||= submit_default_value
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 90fa1f3520..eef426703d 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -98,6 +98,7 @@ module ActionView
# <option value="3">Jokes</option>
# <option value="4">Poems</option>
# </select>
+ #
module FormOptionsHelper
# ERB::Util can mask some helpers like textilize. Make sure to include them.
include TextHelper
@@ -153,6 +154,7 @@ module ActionView
# key in the query string, that works for ordinary forms.
#
# In case if you don't want the helper to generate this hidden field you can specify <tt>:include_blank => false</tt> option.
+ #
def select(object, method, choices, options = {}, html_options = {})
Tags::Select.new(object, method, self, choices, options, html_options).render
end
@@ -239,6 +241,7 @@ module ActionView
# <option value="2">Ireland</option>
# </optgroup>
# </select>
+ #
def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
Tags::GroupedCollectionSelect.new(object, method, self, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options).render
end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 07453c4b50..1a0019a48c 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -63,6 +63,7 @@ module ActionView
#
# form_tag('http://far.away.com/form', :authenticity_token => "cf50faa3fe97702ca1ae")
# # form with custom authenticity token
+ #
def form_tag(url_for_options = {}, options = {}, &block)
html_options = html_options_for_form(url_for_options, options)
if block_given?
@@ -408,6 +409,7 @@ module ActionView
#
# submit_tag "Save", :confirm => "Are you sure?"
# # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
+ #
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
@@ -444,6 +446,7 @@ module ActionView
# # => <button name="button" type="button">
# # <strong>Ask me!</strong>
# # </button>
+ #
def button_tag(content_or_options = nil, options = nil, &block)
options = content_or_options if block_given? && content_or_options.is_a?(Hash)
options ||= {}
@@ -521,6 +524,14 @@ module ActionView
output.safe_concat("</fieldset>")
end
+ # Creates a text field of type "color".
+ #
+ # ==== Options
+ # * Accepts the same options as text_field_tag.
+ def color_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "color"))
+ end
+
# Creates a text field of type "search".
#
# ==== Options
@@ -557,6 +568,50 @@ module ActionView
text_field_tag(name, value, options.stringify_keys.update("type" => "time"))
end
+ # Creates a text field of type "datetime".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def datetime_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "datetime"))
+ end
+
+ # Creates a text field of type "datetime-local".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def datetime_local_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "datetime-local"))
+ end
+
+ # Creates a text field of type "month".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def month_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "month"))
+ end
+
+ # Creates a text field of type "week".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def week_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "week"))
+ end
+
# Creates a text field of type "url".
#
# ==== Options
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 9e43a1faf1..dfc26acfad 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -514,6 +514,7 @@ module ActionView
# number_to_human(343, :units => :distance, :precision => 1) # => "300 meters"
# number_to_human(1, :units => :distance) # => "1 meter"
# number_to_human(0.34, :units => :distance) # => "34 centimeters"
+ #
def number_to_human(number, options = {})
options = options.symbolize_keys
diff --git a/actionpack/lib/action_view/helpers/output_safety_helper.rb b/actionpack/lib/action_view/helpers/output_safety_helper.rb
index 891dd859fa..2e7e9dc50c 100644
--- a/actionpack/lib/action_view/helpers/output_safety_helper.rb
+++ b/actionpack/lib/action_view/helpers/output_safety_helper.rb
@@ -26,6 +26,7 @@ module ActionView #:nodoc:
#
# safe_join(["<p>foo</p>".html_safe, "<p>bar</p>".html_safe], "<br />".html_safe)
# # => "<p>foo</p><br /><p>bar</p>"
+ #
def safe_join(array, sep=$,)
sep = ERB::Util.html_escape(sep)
diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb
index 8734136f39..9b35f076e5 100644
--- a/actionpack/lib/action_view/helpers/record_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb
@@ -29,6 +29,7 @@ module ActionView
#
# <div id="person_123" class="person foo"> Joe Bloggs </div>
# <div id="person_124" class="person foo"> Jane Bloggs </div>
+ #
def div_for(record, *args, &block)
content_tag_for(:div, record, *args, &block)
end
@@ -78,6 +79,7 @@ module ActionView
# produces:
#
# <li id="person_123" class="person bar">...
+ #
def content_tag_for(tag_name, single_or_multiple_records, prefix = nil, options = nil, &block)
options, prefix = prefix, nil if prefix.is_a?(Hash)
diff --git a/actionpack/lib/action_view/helpers/rendering_helper.rb b/actionpack/lib/action_view/helpers/rendering_helper.rb
index 55fb443929..626e1a1ab7 100644
--- a/actionpack/lib/action_view/helpers/rendering_helper.rb
+++ b/actionpack/lib/action_view/helpers/rendering_helper.rb
@@ -75,6 +75,7 @@ module ActionView
# <html>
# Hello David
# </html>
+ #
def _layout_for(*args, &block)
name = args.first
diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index ba74217c12..a727b910e5 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -55,6 +55,7 @@ module ActionView
# resulting markup is valid (conforming to a document type) or even well-formed.
# The output may still contain e.g. unescaped '<', '>', '&' characters and
# confuse browsers.
+ #
def sanitize(html, options = {})
self.class.white_list_sanitizer.sanitize(html, options).try(:html_safe)
end
@@ -143,6 +144,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.full_sanitizer = MySpecialSanitizer.new
# end
+ #
def full_sanitizer
@full_sanitizer ||= HTML::FullSanitizer.new
end
@@ -153,6 +155,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.link_sanitizer = MySpecialSanitizer.new
# end
+ #
def link_sanitizer
@link_sanitizer ||= HTML::LinkSanitizer.new
end
@@ -163,6 +166,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.white_list_sanitizer = MySpecialSanitizer.new
# end
+ #
def white_list_sanitizer
@white_list_sanitizer ||= HTML::WhiteListSanitizer.new
end
@@ -172,6 +176,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.sanitized_uri_attributes = 'lowsrc', 'target'
# end
+ #
def sanitized_uri_attributes=(attributes)
HTML::WhiteListSanitizer.uri_attributes.merge(attributes)
end
@@ -181,6 +186,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.sanitized_bad_tags = 'embed', 'object'
# end
+ #
def sanitized_bad_tags=(attributes)
HTML::WhiteListSanitizer.bad_tags.merge(attributes)
end
@@ -190,6 +196,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
# end
+ #
def sanitized_allowed_tags=(attributes)
HTML::WhiteListSanitizer.allowed_tags.merge(attributes)
end
@@ -199,6 +206,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.sanitized_allowed_attributes = 'onclick', 'longdesc'
# end
+ #
def sanitized_allowed_attributes=(attributes)
HTML::WhiteListSanitizer.allowed_attributes.merge(attributes)
end
@@ -208,6 +216,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.sanitized_allowed_css_properties = 'expression'
# end
+ #
def sanitized_allowed_css_properties=(attributes)
HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes)
end
@@ -217,6 +226,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.sanitized_allowed_css_keywords = 'expression'
# end
+ #
def sanitized_allowed_css_keywords=(attributes)
HTML::WhiteListSanitizer.allowed_css_keywords.merge(attributes)
end
@@ -226,6 +236,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.sanitized_shorthand_css_properties = 'expression'
# end
+ #
def sanitized_shorthand_css_properties=(attributes)
HTML::WhiteListSanitizer.shorthand_css_properties.merge(attributes)
end
@@ -235,6 +246,7 @@ module ActionView
# class Application < Rails::Application
# config.action_view.sanitized_allowed_protocols = 'ssh', 'feed'
# end
+ #
def sanitized_allowed_protocols=(attributes)
HTML::WhiteListSanitizer.allowed_protocols.merge(attributes)
end
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index 498be596ad..9572f1c192 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -41,7 +41,7 @@ module ActionView
# thus accessed as <tt>dataset.userId</tt>.
#
# Values are encoded to JSON, with the exception of strings and symbols.
- # This may come in handy when using jQuery's HTML5-aware <tt>.data()<tt>
+ # This may come in handy when using jQuery's HTML5-aware <tt>.data()</tt>
# from 1.4.3.
#
# ==== Examples
diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb
index 5cd77c8ec3..a05e16979a 100644
--- a/actionpack/lib/action_view/helpers/tags.rb
+++ b/actionpack/lib/action_view/helpers/tags.rb
@@ -8,14 +8,18 @@ module ActionView
autoload :CollectionCheckBoxes
autoload :CollectionRadioButtons
autoload :CollectionSelect
+ autoload :ColorField
autoload :DateField
autoload :DateSelect
+ autoload :DatetimeField
+ autoload :DatetimeLocalField
autoload :DatetimeSelect
autoload :EmailField
autoload :FileField
autoload :GroupedCollectionSelect
autoload :HiddenField
autoload :Label
+ autoload :MonthField
autoload :NumberField
autoload :PasswordField
autoload :RadioButton
@@ -29,6 +33,7 @@ module ActionView
autoload :TimeSelect
autoload :TimeZoneSelect
autoload :UrlField
+ autoload :WeekField
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/color_field.rb b/actionpack/lib/action_view/helpers/tags/color_field.rb
new file mode 100644
index 0000000000..6f08f8483a
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/color_field.rb
@@ -0,0 +1,25 @@
+module ActionView
+ module Helpers
+ module Tags
+ class ColorField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["value"] = @options.fetch("value") { validate_color_string(value(object)) }
+ @options = options
+ super
+ end
+
+ private
+
+ def validate_color_string(string)
+ regex = /#[0-9a-fA-F]{6}/
+ if regex.match(string)
+ string.downcase
+ else
+ "#000000"
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionpack/lib/action_view/helpers/tags/date_field.rb
index 0e79609d52..64c29dea3d 100644
--- a/actionpack/lib/action_view/helpers/tags/date_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/date_field.rb
@@ -1,13 +1,12 @@
module ActionView
module Helpers
module Tags
- class DateField < TextField #:nodoc:
- def render
- options = @options.stringify_keys
- options["value"] = @options.fetch("value") { value(object).try(:to_date) }
- @options = options
- super
- end
+ class DateField < DatetimeField #:nodoc:
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-%m-%d")
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/datetime_field.rb b/actionpack/lib/action_view/helpers/tags/datetime_field.rb
new file mode 100644
index 0000000000..e407146e96
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/datetime_field.rb
@@ -0,0 +1,22 @@
+module ActionView
+ module Helpers
+ module Tags
+ class DatetimeField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["value"] = @options.fetch("value") { format_date(value(object)) }
+ options["min"] = format_date(options["min"])
+ options["max"] = format_date(options["max"])
+ @options = options
+ super
+ end
+
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-%m-%dT%T.%L%z")
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb b/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb
new file mode 100644
index 0000000000..6668d6d718
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb
@@ -0,0 +1,19 @@
+module ActionView
+ module Helpers
+ module Tags
+ class DatetimeLocalField < DatetimeField #:nodoc:
+ class << self
+ def field_type
+ @field_type ||= "datetime-local"
+ end
+ end
+
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-%m-%dT%T")
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/month_field.rb b/actionpack/lib/action_view/helpers/tags/month_field.rb
new file mode 100644
index 0000000000..3d3c32d847
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/month_field.rb
@@ -0,0 +1,13 @@
+module ActionView
+ module Helpers
+ module Tags
+ class MonthField < DatetimeField #:nodoc:
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-%m")
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/select.rb b/actionpack/lib/action_view/helpers/tags/select.rb
index 4d94ee2c23..53a108b7e6 100644
--- a/actionpack/lib/action_view/helpers/tags/select.rb
+++ b/actionpack/lib/action_view/helpers/tags/select.rb
@@ -31,6 +31,7 @@ module ActionView
#
# [nil, []]
# { nil => [] }
+ #
def grouped_choices?
!@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last
end
diff --git a/actionpack/lib/action_view/helpers/tags/time_field.rb b/actionpack/lib/action_view/helpers/tags/time_field.rb
index 271dc00c54..a3941860c9 100644
--- a/actionpack/lib/action_view/helpers/tags/time_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/time_field.rb
@@ -1,13 +1,12 @@
module ActionView
module Helpers
module Tags
- class TimeField < TextField #:nodoc:
- def render
- options = @options.stringify_keys
- options["value"] = @options.fetch("value") { value(object).try(:strftime, "%T.%L") }
- @options = options
- super
- end
+ class TimeField < DatetimeField #:nodoc:
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%T.%L")
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/week_field.rb b/actionpack/lib/action_view/helpers/tags/week_field.rb
new file mode 100644
index 0000000000..1e13939a0a
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/week_field.rb
@@ -0,0 +1,13 @@
+module ActionView
+ module Helpers
+ module Tags
+ class WeekField < DatetimeField #:nodoc:
+ private
+
+ def format_date(value)
+ value.try(:strftime, "%Y-W%W")
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 8cd7cf0052..0cc0d069ea 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -62,9 +62,11 @@ module ActionView
#
# Pass a <tt>:separator</tt> to truncate +text+ at a natural break.
#
- # The result is not marked as HTML-safe, so will be subject to the default escaping when
- # used in views, unless wrapped by <tt>raw()</tt>. Care should be taken if +text+ contains HTML tags
- # or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags).
+ # Pass a block if you want to show extra content when the text is truncated.
+ #
+ # The result is marked as HTML-safe, but it is escaped by default, unless <tt>:escape</tt> is
+ # +false+. Care should be taken if +text+ contains HTML tags or entities, because truncation
+ # may produce invalid HTML (such as unbalanced or incomplete tags).
#
# truncate("Once upon a time in a world far far away")
# # => "Once upon a time in a world..."
@@ -80,8 +82,18 @@ module ActionView
#
# truncate("<p>Once upon a time in a world far far away</p>")
# # => "<p>Once upon a time in a wo..."
- def truncate(text, options = {})
- text.truncate(options.fetch(:length, 30), options) if text
+ #
+ # truncate("Once upon a time in a world far far away") { link_to "Continue", "#" }
+ # # => "Once upon a time in a wo...<a href="#">Continue</a>"
+ def truncate(text, options = {}, &block)
+ if text
+ length = options.fetch(:length, 30)
+
+ content = text.truncate(length, options)
+ content = options[:escape] == false ? content.html_safe : ERB::Util.html_escape(content)
+ content << capture(&block) if block_given? && text.length > length
+ content
+ end
end
# Highlights one or more +phrases+ everywhere in +text+ by inserting it into
@@ -102,7 +114,7 @@ module ActionView
# # => You searched for: <a href="search?q=rails">rails</a>
def highlight(text, phrases, options = {})
highlighter = options.fetch(:highlighter, '<mark>\1</mark>')
-
+
text = sanitize(text) if options.fetch(:sanitize, true)
if text.blank? || phrases.blank?
text
@@ -165,12 +177,12 @@ module ActionView
# pluralize(0, 'person')
# # => 0 people
def pluralize(count, singular, plural = nil)
- word = if (count == 1 || count =~ /^1(\.0+)?$/)
- singular
+ word = if (count == 1 || count =~ /^1(\.0+)?$/)
+ singular
else
plural || singular.pluralize
end
-
+
"#{count || 0} #{word}"
end
@@ -215,7 +227,7 @@ module ActionView
#
# simple_format(my_text)
# # => "<p>Here is some basic text...\n<br />...with a line break.</p>"
- #
+ #
# simple_format(my_text, {}, :wrapper_tag => "div")
# # => "<div>Here is some basic text...\n<br />...with a line break.</div>"
#
@@ -231,7 +243,7 @@ module ActionView
# # => "<p><span>I'm allowed!</span> It's true.</p>"
def simple_format(text, html_options = {}, options = {})
wrapper_tag = options.fetch(:wrapper_tag, :p)
-
+
text = sanitize(text) if options.fetch(:sanitize, true)
paragraphs = split_paragraphs(text)
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index 8171bea8ed..552c9ba660 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -64,7 +64,7 @@ module ActionView
# Delegates to <tt>I18n.localize</tt> with no additional functionality.
#
- # See http://rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
+ # See http://rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
# for more information.
def localize(*args)
I18n.localize(*args)
@@ -96,7 +96,7 @@ module ActionView
new_defaults << lambda { |_, options| translate key, options.merge(:default => defaults) }
break
else
- new_defautls << key
+ new_defaults << key
end
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 2e45a2ae0f..7e69547dab 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -586,6 +586,7 @@ module ActionView
#
# current_page?(:controller => 'product', :action => 'index')
# # => false
+ #
def current_page?(options)
unless request
raise "You cannot use helpers that need to determine the current " \
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index edb3d427d5..cd79468502 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/try'
require 'active_support/core_ext/kernel/singleton_class'
+require 'thread'
module ActionView
# = Action View Template
@@ -122,6 +123,7 @@ module ActionView
@virtual_path = details[:virtual_path]
@updated_at = details[:updated_at] || Time.now
@formats = Array(format).map { |f| f.is_a?(Mime::Type) ? f.ref : f }
+ @compile_mutex = Mutex.new
end
# Returns if the underlying handler supports streaming. If so,
@@ -223,18 +225,28 @@ module ActionView
def compile!(view) #:nodoc:
return if @compiled
- if view.is_a?(ActionView::CompiledTemplates)
- mod = ActionView::CompiledTemplates
- else
- mod = view.singleton_class
- end
+ # Templates can be used concurrently in threaded environments
+ # so compilation and any instance variable modification must
+ # be synchronized
+ @compile_mutex.synchronize do
+ # Any thread holding this lock will be compiling the template needed
+ # by the threads waiting. So re-check the @compiled flag to avoid
+ # re-compilation
+ return if @compiled
+
+ if view.is_a?(ActionView::CompiledTemplates)
+ mod = ActionView::CompiledTemplates
+ else
+ mod = view.singleton_class
+ end
- compile(view, mod)
+ compile(view, mod)
- # Just discard the source if we have a virtual path. This
- # means we can get the template back.
- @source = nil if @virtual_path
- @compiled = true
+ # Just discard the source if we have a virtual path. This
+ # means we can get the template back.
+ @source = nil if @virtual_path
+ @compiled = true
+ end
end
# Among other things, this method is responsible for properly setting
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index d267a8466a..fa2038f78d 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -215,6 +215,7 @@ module ActionView
# * <tt>:locale</tt> - possible locale versions
# * <tt>:formats</tt> - possible request formats (for example html, json, xml...)
# * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
+ #
class FileSystemResolver < PathResolver
def initialize(path, pattern=nil)
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)