aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb17
-rw-r--r--actionpack/lib/action_controller/base.rb16
-rw-r--r--actionpack/lib/action_controller/caching/fragments.rb1
-rw-r--r--actionpack/lib/action_controller/caching/sweeping.rb1
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb9
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb6
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb6
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb1
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb1
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb30
-rw-r--r--actionpack/lib/action_dispatch/http/headers.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/upload.rb12
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb15
-rw-r--r--actionpack/lib/action_dispatch/middleware/head.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb15
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb3
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb5
-rw-r--r--actionpack/lib/action_dispatch/testing/test_request.rb27
-rw-r--r--actionpack/lib/action_view.rb1
-rw-r--r--actionpack/lib/action_view/asset_paths.rb79
-rw-r--r--actionpack/lib/action_view/buffers.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_paths.rb82
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb3
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/controller_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb13
-rw-r--r--actionpack/lib/action_view/helpers/debug_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb32
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb70
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb11
-rw-r--r--actionpack/lib/action_view/helpers/javascript_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb6
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb28
-rw-r--r--actionpack/lib/action_view/log_subscriber.rb2
-rw-r--r--actionpack/lib/action_view/lookup_context.rb2
-rw-r--r--actionpack/lib/action_view/renderer/template_renderer.rb2
-rw-r--r--actionpack/lib/action_view/template/error.rb1
-rw-r--r--actionpack/lib/action_view/testing/resolvers.rb2
-rw-r--r--actionpack/lib/sprockets/helpers/rails_helper.rb71
-rw-r--r--actionpack/lib/sprockets/railtie.rb84
44 files changed, 376 insertions, 311 deletions
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index 8f73e244d7..d6f75bded0 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -81,11 +81,12 @@ module AbstractController
# class EmployeeController < BankController
# layout nil
#
- # The InformationController uses "bank_standard" inherited from the BankController, the VaultController overwrites
- # and picks the layout dynamically, and the EmployeeController doesn't want to use a layout at all.
- #
- # The TellerController uses +teller.html.erb+, and TillController inherits that layout and
- # uses it as well.
+ # In these examples:
+ # * The InformationController uses the "bank_standard" layout, inherited from BankController.
+ # * The TellerController follows convention and uses +app/views/layouts/teller.html.erb+.
+ # * The TillController inherits the layout from TellerController and uses +teller.html.erb+ as well.
+ # * The VaultController chooses a layout dynamically by calling the <tt>access_level_layout</tt> method.
+ # * The EmployeeController does not use a layout at all.
#
# == Types of layouts
#
@@ -138,8 +139,8 @@ module AbstractController
#
# end
#
- # This will assign "weblog_standard" as the WeblogController's layout except for the +rss+ action, which will not wrap a layout
- # around the rendered view.
+ # This will assign "weblog_standard" as the WeblogController's layout for all actions except for the +rss+ action, which will
+ # be rendered directly, without wrapping a layout around the rendered view.
#
# Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
# #<tt>:except => [ :rss, :text_only ]</tt> is valid, as is <tt>:except => :rss</tt>.
@@ -158,7 +159,7 @@ module AbstractController
# end
# end
#
- # This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout.
+ # This will override the controller-wide "weblog_standard" layout, and will render the help action with the "help" layout instead.
module Layouts
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index c03c77cb4a..d14c5f940b 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -31,7 +31,7 @@ module ActionController
# "302 Moved" HTTP response that takes the user to the index action.
#
# These two methods represent the two basic action archetypes used in Action Controllers. Get-and-show and do-and-redirect.
- # Most actions are variations of these themes.
+ # Most actions are variations on these themes.
#
# == Requests
#
@@ -116,8 +116,8 @@ module ActionController
#
# Title: <%= @post.title %>
#
- # You don't have to rely on the automated rendering. Especially actions that could result in the rendering of different templates will use
- # the manual rendering methods:
+ # You don't have to rely on the automated rendering. For example, actions that could result in the rendering of different templates
+ # will use the manual rendering methods:
#
# def search
# @results = Search.find(params[:query])
@@ -132,9 +132,9 @@ module ActionController
#
# == Redirects
#
- # Redirects are used to move from one action to another. For example, after a <tt>create</tt> action, which stores a blog entry to a database,
- # we might like to show the user the new entry. Because we're following good DRY principles (Don't Repeat Yourself), we're going to reuse (and redirect to)
- # a <tt>show</tt> action that we'll assume has already been created. The code might look like this:
+ # Redirects are used to move from one action to another. For example, after a <tt>create</tt> action, which stores a blog entry to the
+ # database, we might like to show the user the new entry. Because we're following good DRY principles (Don't Repeat Yourself), we're
+ # going to reuse (and redirect to) a <tt>show</tt> action that we'll assume has already been created. The code might look like this:
#
# def create
# @entry = Entry.new(params[:entry])
@@ -146,7 +146,9 @@ module ActionController
# end
# end
#
- # In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method which is then executed.
+ # In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method, which is then executed.
+ # Note that this is an external HTTP-level redirection which will cause the browser to make a second request (a GET to the show action),
+ # and not some internal re-routing which calls both "create" and then "show" within one request.
#
# Learn more about <tt>redirect_to</tt> and what options you have in ActionController::Redirecting.
#
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index 0be04b70a1..2bdb23c4d7 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -109,7 +109,6 @@ module ActionController #:nodoc:
def expire_fragment(key, options = nil)
return unless cache_configured?
key = fragment_cache_key(key) unless key.is_a?(Regexp)
- message = nil
instrument_fragment_cache :expire_fragment, key do
if key.is_a?(Regexp)
diff --git a/actionpack/lib/action_controller/caching/sweeping.rb b/actionpack/lib/action_controller/caching/sweeping.rb
index e9db0d97b6..938a6ae81c 100644
--- a/actionpack/lib/action_controller/caching/sweeping.rb
+++ b/actionpack/lib/action_controller/caching/sweeping.rb
@@ -61,6 +61,7 @@ module ActionController #:nodoc:
end
def after(controller)
+ self.controller = controller
callback(:after) if controller.perform_caching
# Clean up, so that the controller can be collected after this request
self.controller = nil
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index 8d813a8e38..35e29398e6 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -10,7 +10,7 @@ module ActionController
format = payload[:format]
format = format.to_s.upcase if format.is_a?(Symbol)
- info " Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
+ info "Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
info " Parameters: #{params.inspect}" unless params.empty?
end
@@ -20,10 +20,11 @@ module ActionController
status = payload[:status]
if status.nil? && payload[:exception].present?
- status = Rack::Utils.status_code(ActionDispatch::ShowExceptions.rescue_responses[payload[:exception].first]) rescue nil
- end
+ status = Rack::Utils.status_code(ActionDispatch::ShowExceptions.rescue_responses[payload[:exception].first]) rescue nil
+ end
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in %.0fms" % event.duration
message << " (#{additions.join(" | ")})" unless additions.blank?
+ message << "\n"
info(message)
end
@@ -59,4 +60,4 @@ module ActionController
end
end
-ActionController::LogSubscriber.attach_to :action_controller \ No newline at end of file
+ActionController::LogSubscriber.attach_to :action_controller
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 2ad571b2b5..7420a5e7e9 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -106,7 +106,7 @@ module ActionController
module ControllerMethods
extend ActiveSupport::Concern
-
+
module ClassMethods
def http_basic_authenticate_with(options = {})
before_filter(options.except(:name, :password, :realm)) do
@@ -116,7 +116,7 @@ module ActionController
end
end
end
-
+
def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
end
@@ -423,7 +423,7 @@ module ActionController
# Returns an Array of [String, Hash] if a token is present.
# Returns nil if no token is found.
def token_and_options(request)
- if header = request.authorization.to_s[/^Token (.*)/]
+ if request.authorization.to_s[/^Token (.*)/]
values = Hash[$1.split(',').map do |value|
value.strip! # remove any spaces between commas and values
key, value = value.split(/\=\"?/) # split key=value pairs
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index 5500f88930..2d8afc3a78 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -64,7 +64,7 @@ module ActionController
# end
#
# will try to check if +Admin::User+ or +User+ model exists, and use it to
- # determine the wrapper key respectively. If both of the model doesn't exists,
+ # determine the wrapper key respectively. If both models don't exist,
# it will then fallback to use +user+ as the key.
module ParamsWrapper
extend ActiveSupport::Concern
@@ -88,14 +88,14 @@ module ActionController
# # wraps parameters into +params[:person]+ hash
#
# wrap_parameters Person
- # # wraps parameters by determine the wrapper key from Person class
+ # # wraps parameters by determining the wrapper key from Person class
# (+person+, in this case) and the list of attribute names
#
# wrap_parameters :include => [:username, :title]
# # wraps only +:username+ and +:title+ attributes from parameters.
#
# wrap_parameters false
- # # disable parameters wrapping for this controller altogether.
+ # # disables parameters wrapping for this controller altogether.
#
# ==== Options
# * <tt>:format</tt> - The list of formats in which the parameters wrapper
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 55c650df6c..dee7eb1ec8 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -43,6 +43,7 @@ module ActionController
#
# The status code can either be a standard {HTTP Status code}[http://www.iana.org/assignments/http-status-codes] as an
# integer, or a symbol representing the downcased, underscored and symbolized description.
+ # Note that the status code must be a 3xx HTTP code, or redirection will not occur.
#
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
# +alert+ and +notice+ as well as a general purpose +flash+ bucket.
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 3892a12407..0bb436a476 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -260,4 +260,3 @@ module ActionController #:nodoc:
end
end
end
- \ No newline at end of file
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index 2def78b51a..c11d676c5e 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -40,7 +40,7 @@ module ActionController
# dom_class(post, :edit) # => "edit_post"
# dom_class(Person, :edit) # => "edit_person"
def dom_class(record_or_class, prefix = nil)
- singular = ActiveModel::Naming.singular(record_or_class)
+ singular = ActiveModel::Naming.param_key(record_or_class)
prefix ? "#{prefix}#{JOIN}#{singular}" : singular
end
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index bfb820fcdf..45bb641aee 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -175,10 +175,6 @@ module ActionController
end
def recycle!
- write_cookies!
- @env.delete('HTTP_COOKIE') if @cookies.blank?
- @env.delete('action_dispatch.cookies')
- @cookies = nil
@formats = nil
@env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
@env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
@@ -186,6 +182,14 @@ module ActionController
@method = @request_method = nil
@fullpath = @ip = @remote_ip = nil
@env['action_dispatch.request.query_parameters'] = {}
+ @set_cookies ||= {}
+ @set_cookies.update(Hash[cookie_jar.instance_variable_get("@set_cookies").map{ |k,o| [k,o[:value]] }])
+ deleted_cookies = cookie_jar.instance_variable_get("@delete_cookies")
+ @set_cookies.reject!{ |k,v| deleted_cookies.include?(k) }
+ cookie_jar.update(rack_cookies)
+ cookie_jar.update(cookies)
+ cookie_jar.update(@set_cookies)
+ cookie_jar.recycle!
end
end
@@ -206,7 +210,7 @@ module ActionController
DEFAULT_OPTIONS = Rack::Session::Abstract::ID::DEFAULT_OPTIONS
def initialize(session = {})
- @env, @by = nil, nil
+ super(nil, nil)
replace(session.stringify_keys)
@loaded = true
end
@@ -301,18 +305,17 @@ module ActionController
# For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another
# action call which can then be asserted against.
#
- # == Manipulating the request collections
+ # == Manipulating session and cookie variables
#
- # The collections described above link to the response, so you can test if what the actions were expected to do happened. But
- # sometimes you also want to manipulate these collections in the incoming request. This is really only relevant for sessions
- # and cookies, though. For sessions, you just do:
+ # Sometimes you need to set up the session and cookie variables for a test.
+ # To do this just assign a value to the session or cookie collection:
#
- # @request.session[:key] = "value"
- # @request.cookies[:key] = "value"
+ # session[:key] = "value"
+ # cookies[:key] = "value"
#
- # To clear the cookies for a test just clear the request's cookies hash:
+ # To clear the cookies for a test just clear the cookie collection:
#
- # @request.cookies.clear
+ # cookies.clear
#
# == \Testing named routes
#
@@ -450,7 +453,6 @@ module ActionController
@controller.process_with_new_base_test(@request, @response)
@assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
@request.session.delete('flash') if @request.session['flash'].blank?
- @request.cookies.merge!(@response.cookies)
@response
end
diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb
index 1e43104f0a..505d5560b1 100644
--- a/actionpack/lib/action_dispatch/http/headers.rb
+++ b/actionpack/lib/action_dispatch/http/headers.rb
@@ -3,9 +3,10 @@ require 'active_support/memoizable'
module ActionDispatch
module Http
class Headers < ::Hash
- extend ActiveSupport::Memoizable
+ @@env_cache = Hash.new { |h,k| h[k] = "HTTP_#{k.upcase.gsub(/-/, '_')}" }
def initialize(*args)
+
if args.size == 1 && args[0].is_a?(Hash)
super()
update(args[0])
@@ -25,9 +26,8 @@ module ActionDispatch
private
# Converts a HTTP header name to an environment variable name.
def env_name(header_name)
- "HTTP_#{header_name.upcase.gsub(/-/, '_')}"
+ @@env_cache[header_name]
end
- memoize :env_name
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb
index 37effade4f..a15ad28f16 100644
--- a/actionpack/lib/action_dispatch/http/upload.rb
+++ b/actionpack/lib/action_dispatch/http/upload.rb
@@ -4,7 +4,7 @@ module ActionDispatch
attr_accessor :original_filename, :content_type, :tempfile, :headers
def initialize(hash)
- @original_filename = hash[:filename]
+ @original_filename = encode_filename(hash[:filename])
@content_type = hash[:type]
@headers = hash[:head]
@tempfile = hash[:tempfile]
@@ -30,6 +30,16 @@ module ActionDispatch
def size
@tempfile.size
end
+
+ private
+ def encode_filename(filename)
+ # Encode the filename in the utf8 encoding, unless it is nil or we're in 1.8
+ if "ruby".encoding_aware? && filename
+ filename.force_encoding("UTF-8").encode!
+ else
+ filename
+ end
+ end
end
module Upload
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 47c4bad489..8cee9ecdc4 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -1,4 +1,5 @@
-require "active_support/core_ext/object/blank"
+require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/hash/keys'
module ActionDispatch
class Request
@@ -129,7 +130,7 @@ module ActionDispatch
end
def update(other_hash)
- @cookies.update other_hash
+ @cookies.update other_hash.stringify_keys
self
end
@@ -185,6 +186,11 @@ module ActionDispatch
value
end
+ # Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie
+ def clear(options = {})
+ @cookies.each_key{ |k| delete(k, options) }
+ end
+
# Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example:
#
# cookies.permanent[:prefers_open_id] = true
@@ -222,6 +228,11 @@ module ActionDispatch
@delete_cookies.each { |k, v| ::Rack::Utils.delete_cookie_header!(headers, k, v) }
end
+ def recycle! #:nodoc:
+ @set_cookies.clear
+ @delete_cookies.clear
+ end
+
private
def write_cookie?(cookie)
diff --git a/actionpack/lib/action_dispatch/middleware/head.rb b/actionpack/lib/action_dispatch/middleware/head.rb
index 56e2d2f2a8..f1906a3ab3 100644
--- a/actionpack/lib/action_dispatch/middleware/head.rb
+++ b/actionpack/lib/action_dispatch/middleware/head.rb
@@ -8,7 +8,7 @@ module ActionDispatch
if env["REQUEST_METHOD"] == "HEAD"
env["REQUEST_METHOD"] = "GET"
env["rack.methodoverride.original_method"] = "HEAD"
- status, headers, body = @app.call(env)
+ status, headers, _ = @app.call(env)
[status, headers, []]
else
@app.call(env)
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 74c090f260..1dcd83ceb5 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -161,7 +161,7 @@ module ActionDispatch
# Consider the following route, which you will find commented out at the
# bottom of your generated <tt>config/routes.rb</tt>:
#
- # match ':controller(/:action(/:id(.:format)))'
+ # match ':controller(/:action(/:id))(.:format)'
#
# This route states that it expects requests to consist of a
# <tt>:controller</tt> followed optionally by an <tt>:action</tt> that in
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index ec76d1da1e..65895590bf 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -49,6 +49,9 @@ module ActionDispatch
class Mapping #:nodoc:
IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix]
+ ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
+ SHORTHAND_REGEX = %r{^/[\w/]+$}
+ WILDCARD_PATH = %r{\*([^/]+)$}
def initialize(set, scope, path, options)
@set, @scope = set, scope
@@ -77,7 +80,7 @@ module ActionDispatch
# segment_keys.include?(k.to_s) || k == :controller
next unless Regexp === requirement && !constraints[name]
- if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
+ if requirement.source =~ ANCHOR_CHARACTERS_REGEX
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
end
if requirement.multiline?
@@ -88,7 +91,7 @@ module ActionDispatch
# match "account/overview"
def using_match_shorthand?(path, options)
- path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$}
+ path && options.except(:via, :anchor, :to, :as).empty? && path =~ SHORTHAND_REGEX
end
def normalize_path(path)
@@ -107,7 +110,7 @@ module ActionDispatch
# Add a constraint for wildcard route to make it non-greedy and match the
# optional format part of the route by default
- if path.match(/\*([^\/]+)$/) && @options[:format] != false
+ if path.match(WILDCARD_PATH) && @options[:format] != false
@options.reverse_merge!(:"#{$1}" => /.+?/)
end
@@ -1102,9 +1105,9 @@ module ActionDispatch
#
# The +comments+ resource here will have the following routes generated for it:
#
- # post_comments GET /sekret/posts/:post_id/comments(.:format)
- # post_comments POST /sekret/posts/:post_id/comments(.:format)
- # new_post_comment GET /sekret/posts/:post_id/comments/new(.:format)
+ # post_comments GET /posts/:post_id/comments(.:format)
+ # post_comments POST /posts/:post_id/comments(.:format)
+ # new_post_comment GET /posts/:post_id/comments/new(.:format)
# edit_comment GET /sekret/comments/:id/edit(.:format)
# comment GET /sekret/comments/:id(.:format)
# comment PUT /sekret/comments/:id(.:format)
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 9791ba58e2..aae5752c93 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -207,9 +207,6 @@ module ActionDispatch
"*/*;q=0.5"
unless defined? @named_routes_configured
- # install the named routes in this session instance.
- klass = singleton_class
-
# the helpers are made protected by default--we make them public for
# easier access during testing and troubleshooting.
@named_routes_configured = true
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
index 397bda41d5..f668b81b45 100644
--- a/actionpack/lib/action_dispatch/testing/test_process.rb
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -1,3 +1,4 @@
+require 'action_dispatch/middleware/cookies'
require 'action_dispatch/middleware/flash'
require 'active_support/core_ext/hash/indifferent_access'
@@ -22,7 +23,7 @@ module ActionDispatch
end
def cookies
- @request.cookies.merge(@response.cookies).with_indifferent_access
+ @request.cookie_jar
end
def redirect_to_url
@@ -38,7 +39,7 @@ module ActionDispatch
#
# post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
def fixture_file_upload(path, mime_type = nil, binary = false)
- fixture_path = ActionController::TestCase.send(:fixture_path) if ActionController::TestCase.respond_to?(:fixture_path)
+ fixture_path = self.class.fixture_path if self.class.respond_to?(:fixture_path)
Rack::Test::UploadedFile.new("#{fixture_path}#{path}", mime_type, binary)
end
end
diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb
index 822adb6a47..7280e9a93b 100644
--- a/actionpack/lib/action_dispatch/testing/test_request.rb
+++ b/actionpack/lib/action_dispatch/testing/test_request.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/hash/reverse_merge'
require 'rack/utils'
@@ -14,18 +15,11 @@ module ActionDispatch
env = Rails.application.env_config.merge(env) if defined?(Rails.application)
super(DEFAULT_ENV.merge(env))
- @cookies = nil
self.host = 'test.host'
self.remote_addr = '0.0.0.0'
self.user_agent = 'Rails Testing'
end
- def env
- write_cookies!
- delete_nil_values!
- super
- end
-
def request_method=(method)
@env['REQUEST_METHOD'] = method.to_s.upcase
end
@@ -71,23 +65,10 @@ module ActionDispatch
@env['HTTP_ACCEPT'] = Array(mime_types).collect { |mime_type| mime_type.to_s }.join(",")
end
+ alias :rack_cookies :cookies
+
def cookies
- @cookies ||= super
+ @cookies ||= {}.with_indifferent_access
end
-
- private
- def write_cookies!
- unless @cookies.blank?
- @env['HTTP_COOKIE'] = @cookies.map { |name, value| escape_cookie(name, value) }.join('; ')
- end
- end
-
- def escape_cookie(name, value)
- "#{Rack::Utils.escape(name)}=#{Rack::Utils.escape(value)}"
- end
-
- def delete_nil_values!
- @env.delete_if { |k, v| v.nil? }
- end
end
end
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 78eddb7530..d7229419a9 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -30,6 +30,7 @@ module ActionView
extend ActiveSupport::Autoload
eager_autoload do
+ autoload :AssetPaths
autoload :Base
autoload :Context
autoload :Helpers
diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb
new file mode 100644
index 0000000000..2b1fe545a6
--- /dev/null
+++ b/actionpack/lib/action_view/asset_paths.rb
@@ -0,0 +1,79 @@
+require 'active_support/core_ext/file'
+
+module ActionView
+ class AssetPaths #:nodoc:
+ attr_reader :config, :controller
+
+ def initialize(config, controller)
+ @config = config
+ @controller = controller
+ end
+
+ # Add the extension +ext+ if not present. Return full or scheme-relative URLs otherwise untouched.
+ # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
+ # roots. Rewrite the asset path for cache-busting asset ids. Include
+ # asset host, if configured, with the correct request protocol.
+ def compute_public_path(source, dir, ext = nil, include_host = true)
+ source = source.to_s
+ return source if is_uri?(source)
+
+ source = rewrite_extension(source, dir, ext) if ext
+ source = rewrite_asset_path(source, dir)
+
+ if controller && include_host
+ has_request = controller.respond_to?(:request)
+ source = rewrite_host_and_protocol(source, has_request)
+ end
+
+ source
+ end
+
+ def is_uri?(path)
+ path =~ %r{^[-a-z]+://|^cid:|^//}
+ end
+
+ private
+
+ def rewrite_extension(source, dir, ext)
+ raise NotImplementedError
+ end
+
+ def rewrite_asset_path(source, path = nil)
+ raise NotImplementedError
+ end
+
+ def rewrite_relative_url_root(source, relative_url_root)
+ relative_url_root && !source.starts_with?("#{relative_url_root}/") ? "#{relative_url_root}#{source}" : source
+ end
+
+ def rewrite_host_and_protocol(source, has_request)
+ source = rewrite_relative_url_root(source, controller.config.relative_url_root) if has_request
+ host = compute_asset_host(source)
+ if has_request && host && !is_uri?(host)
+ host = "#{controller.request.protocol}#{host}"
+ end
+ "#{host}#{source}"
+ end
+
+ # Pick an asset host for this source. Returns +nil+ if no host is set,
+ # the host if no wildcard is set, the host interpolated with the
+ # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4),
+ # or the value returned from invoking call on an object responding to call
+ # (proc or otherwise).
+ def compute_asset_host(source)
+ if host = config.asset_host
+ if host.respond_to?(:call)
+ case host.is_a?(Proc) ? host.arity : host.method(:call).arity
+ when 2
+ request = controller.respond_to?(:request) && controller.request
+ host.call(source, request)
+ else
+ host.call(source)
+ end
+ else
+ (host =~ /%d/) ? host % (source.hash % 4) : host
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/buffers.rb b/actionpack/lib/action_view/buffers.rb
index 089fc68706..be7f65c2ce 100644
--- a/actionpack/lib/action_view/buffers.rb
+++ b/actionpack/lib/action_view/buffers.rb
@@ -35,9 +35,9 @@ module ActionView
def html_safe?
true
end
-
+
def html_safe
self
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_paths.rb
index 9a99c3cf52..fae2e4fc1c 100644
--- a/actionpack/lib/action_view/helpers/asset_paths.rb
+++ b/actionpack/lib/action_view/helpers/asset_paths.rb
@@ -1,83 +1,7 @@
-require 'active_support/core_ext/file'
+ActiveSupport::Deprecation.warn "ActionView::Helpers::AssetPaths is deprecated. Please use ActionView::AssetPaths instead."
module ActionView
module Helpers
-
- class AssetPaths #:nodoc:
- attr_reader :config, :controller
-
- def initialize(config, controller)
- @config = config
- @controller = controller
- end
-
- # Add the extension +ext+ if not present. Return full or scheme-relative URLs otherwise untouched.
- # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
- # roots. Rewrite the asset path for cache-busting asset ids. Include
- # asset host, if configured, with the correct request protocol.
- def compute_public_path(source, dir, ext = nil, include_host = true)
- source = source.to_s
- return source if is_uri?(source)
-
- source = rewrite_extension(source, dir, ext) if ext
- source = rewrite_asset_path(source, dir)
-
- if controller && include_host
- has_request = controller.respond_to?(:request)
- source = rewrite_host_and_protocol(source, has_request)
- end
-
- source
- end
-
- def is_uri?(path)
- path =~ %r{^[-a-z]+://|^cid:|^//}
- end
-
- private
-
- def rewrite_extension(source, dir, ext)
- raise NotImplementedError
- end
-
- def rewrite_asset_path(source, path = nil)
- raise NotImplementedError
- end
-
- def rewrite_relative_url_root(source, relative_url_root)
- relative_url_root && !source.starts_with?("#{relative_url_root}/") ? "#{relative_url_root}#{source}" : source
- end
-
- def rewrite_host_and_protocol(source, has_request)
- source = rewrite_relative_url_root(source, controller.config.relative_url_root) if has_request
- host = compute_asset_host(source)
- if has_request && host && !is_uri?(host)
- host = "#{controller.request.protocol}#{host}"
- end
- "#{host}#{source}"
- end
-
- # Pick an asset host for this source. Returns +nil+ if no host is set,
- # the host if no wildcard is set, the host interpolated with the
- # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4),
- # or the value returned from invoking call on an object responding to call
- # (proc or otherwise).
- def compute_asset_host(source)
- if host = config.asset_host
- if host.respond_to?(:call)
- case host.is_a?(Proc) ? host.arity : host.method(:call).arity
- when 2
- request = controller.respond_to?(:request) && controller.request
- host.call(source, request)
- else
- host.call(source)
- end
- else
- (host =~ /%d/) ? host % (source.hash % 4) : host
- end
- end
- end
- end
-
+ AssetPaths = ::ActionView::AssetPaths
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
index 2d49823412..12a304b395 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
@@ -1,11 +1,10 @@
require 'active_support/core_ext/file'
-require 'action_view/helpers/asset_paths'
module ActionView
module Helpers
module AssetTagHelper
- class AssetPaths < ActionView::Helpers::AssetPaths #:nodoc:
+ class AssetPaths < ::ActionView::AssetPaths #:nodoc:
# You can enable or disable the asset tag ids cache.
# With the cache enabled, the asset tag helper methods will make fewer
# expensive file system calls (the default implementation checks the file
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index e81d03b537..f81ce3e31c 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -51,7 +51,11 @@ module ActionView
# This dance is needed because Builder can't use capture
pos = output_buffer.length
yield
+ output_safe = output_buffer.html_safe?
fragment = output_buffer.slice!(pos..-1)
+ if output_safe
+ self.output_buffer = output_buffer.html_safe
+ end
controller.write_fragment(name, fragment, options)
end
end
diff --git a/actionpack/lib/action_view/helpers/controller_helper.rb b/actionpack/lib/action_view/helpers/controller_helper.rb
index db59bca159..1a583e62ae 100644
--- a/actionpack/lib/action_view/helpers/controller_helper.rb
+++ b/actionpack/lib/action_view/helpers/controller_helper.rb
@@ -20,4 +20,4 @@ module ActionView
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 56e3af683b..6a724749f4 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -621,7 +621,6 @@ module ActionView
end
class DateTimeSelector #:nodoc:
- extend ActiveSupport::Memoizable
include ActionView::Helpers::TagHelper
DEFAULT_PREFIX = 'date'.freeze
@@ -786,11 +785,12 @@ module ActionView
# Returns translated month names, but also ensures that a custom month
# name array has a leading nil element.
def month_names
- month_names = @options[:use_month_names] || translated_month_names
- month_names.unshift(nil) if month_names.size < 13
- month_names
+ @month_names ||= begin
+ month_names = @options[:use_month_names] || translated_month_names
+ month_names.unshift(nil) if month_names.size < 13
+ month_names
+ end
end
- memoize :month_names
# Returns translated month names.
# => [nil, "January", "February", "March",
@@ -825,9 +825,8 @@ module ActionView
end
def date_order
- @options[:order] || translated_date_order
+ @date_order ||= @options[:order] || translated_date_order
end
- memoize :date_order
def translated_date_order
I18n.translate(:'date.order', :locale => @options[:locale]) || []
diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb
index cd67851642..c0cc7d347c 100644
--- a/actionpack/lib/action_view/helpers/debug_helper.rb
+++ b/actionpack/lib/action_view/helpers/debug_helper.rb
@@ -30,7 +30,7 @@ module ActionView
begin
Marshal::dump(object)
"<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", "&nbsp; ")}</pre>".html_safe
- rescue Exception => e # errors from Marshal or YAML
+ rescue Exception # errors from Marshal or YAML
# Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback
"<code class='debug_dump'>#{h(object.inspect)}</code>".html_safe
end
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index cb1c13912a..0ef2357368 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -202,13 +202,13 @@ module ActionView
#
# is equivalent to something like:
#
- # <%= form_for @post, :as => :post, :url => post_path(@post), :html => { :class => "new_post", :id => "new_post" } do |f| %>
+ # <%= form_for @post, :as => :post, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %>
# ...
# <% end %>
#
# You can also overwrite the individual conventions, like this:
#
- # <%= form_for(@post, :url => super_post_path(@post)) do |f| %>
+ # <%= form_for(@post, :url => super_posts_path) do |f| %>
# ...
# <% end %>
#
@@ -219,9 +219,9 @@ module ActionView
# <% end %>
#
# If you have an object that needs to be represented as a different
- # parameter, like a Client that acts as a Person:
+ # parameter, like a Person that acts as a Client:
#
- # <%= form_for(@post, :as => :client) do |f| %>
+ # <%= form_for(@person, :as => :client) do |f| %>
# ...
# <% end %>
#
@@ -290,7 +290,7 @@ module ActionView
#
# Example:
#
- # <%= form(@post) do |f| %>
+ # <%= form_for(@post) do |f| %>
# <% f.fields_for(:comments, :include_id => false) do |cf| %>
# ...
# <% end %>
@@ -517,6 +517,18 @@ module ActionView
# end
# end
#
+ # Note that the <tt>projects_attributes=</tt> writer method is in fact
+ # required for fields_for to correctly identify <tt>:projects</tt> as a
+ # collection, and the correct indices to be set in the form markup.
+ #
+ # When projects is already an association on Person you can use
+ # +accepts_nested_attributes_for+ to define the writer method for you:
+ #
+ # class Person < ActiveRecord::Base
+ # has_many :projects
+ # accepts_nested_attributes_for :projects
+ # end
+ #
# This model can now be used with a nested fields_for. The block given to
# the nested fields_for call will be repeated for each instance in the
# collection:
@@ -568,14 +580,6 @@ module ActionView
# ...
# <% end %>
#
- # When projects is already an association on Person you can use
- # +accepts_nested_attributes_for+ to define the writer method for you:
- #
- # class Person < ActiveRecord::Base
- # has_many :projects
- # accepts_nested_attributes_for :projects
- # end
- #
# If you want to destroy any of the associated models through the
# form, you have to enable it first using the <tt>:allow_destroy</tt>
# option for +accepts_nested_attributes_for+:
@@ -1237,7 +1241,7 @@ module ActionView
end
def fields_for(record_name, record_object = nil, fields_options = {}, &block)
- fields_options, record_object = record_object, nil if record_object.is_a?(Hash)
+ fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
fields_options[:builder] ||= options[:builder]
fields_options[:parent_builder] = self
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 794132637c..3dc6d65432 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -128,6 +128,28 @@ module ActionView
# By default, <tt>post.person_id</tt> is the selected option. Specify <tt>:selected => value</tt> to use a different selection
# or <tt>:selected => nil</tt> to leave all options unselected. Similarly, you can specify values to be disabled in the option
# tags by specifying the <tt>:disabled</tt> option. This can either be a single value or an array of values to be disabled.
+ #
+ # ==== Gotcha
+ #
+ # The HTML specification says when +multiple+ parameter passed to select and all options got deselected
+ # web browsers do not send any value to server. Unfortunately this introduces a gotcha:
+ # if an +User+ model has many +roles+ and have +role_ids+ accessor, and in the form that edits roles of the user
+ # the user deselects all roles from +role_ids+ multiple select box, no +role_ids+ parameter is sent. So,
+ # any mass-assignment idiom like
+ #
+ # @user.update_attributes(params[:user])
+ #
+ # wouldn't update roles.
+ #
+ # To prevent this the helper generates an auxiliary hidden field before
+ # every multiple select. The hidden field has the same name as multiple select and blank value.
+ #
+ # This way, the client either sends only the hidden field (representing
+ # the deselected multiple select box), or both fields. Since the HTML specification
+ # says key/value pairs have to be sent in the same order they appear in the
+ # form, and parameters extraction gets the last occurrence of any repeated
+ # key in the query string, that works for ordinary forms.
+ #
def select(object, method, choices, options = {}, html_options = {})
InstanceTag.new(object, method, self, options.delete(:object)).to_select_tag(choices, options, html_options)
end
@@ -427,7 +449,7 @@ module ActionView
#
# Sample usage (Hash):
# grouped_options = {
- # 'North America' => [['United States','US], 'Canada'],
+ # 'North America' => [['United States','US'], 'Canada'],
# 'Europe' => ['Denmark','Germany','France']
# }
# grouped_options_for_select(grouped_options)
@@ -552,43 +574,26 @@ module ActionView
include FormOptionsHelper
def to_select_tag(choices, options, html_options)
- html_options = html_options.stringify_keys
- add_default_name_and_id(html_options)
- value = value(object)
- selected_value = options.has_key?(:selected) ? options[:selected] : value
- disabled_value = options.has_key?(:disabled) ? options[:disabled] : nil
- content_tag("select", add_options(options_for_select(choices, :selected => selected_value, :disabled => disabled_value), options, selected_value), html_options)
+ selected_value = options.has_key?(:selected) ? options[:selected] : value(object)
+ select_content_tag(options_for_select(choices, :selected => selected_value, :disabled => options[:disabled]), options, html_options)
end
def to_collection_select_tag(collection, value_method, text_method, options, html_options)
- html_options = html_options.stringify_keys
- add_default_name_and_id(html_options)
- value = value(object)
- disabled_value = options.has_key?(:disabled) ? options[:disabled] : nil
- selected_value = options.has_key?(:selected) ? options[:selected] : value
- content_tag(
- "select", add_options(options_from_collection_for_select(collection, value_method, text_method, :selected => selected_value, :disabled => disabled_value), options, value), html_options
+ selected_value = options.has_key?(:selected) ? options[:selected] : value(object)
+ select_content_tag(
+ options_from_collection_for_select(collection, value_method, text_method, :selected => selected_value, :disabled => options[:disabled]), options, html_options
)
end
def to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
- html_options = html_options.stringify_keys
- add_default_name_and_id(html_options)
- value = value(object)
- content_tag(
- "select", add_options(option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, value), options, value), html_options
+ select_content_tag(
+ option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, value(object)), options, html_options
)
end
def to_time_zone_select_tag(priority_zones, options, html_options)
- html_options = html_options.stringify_keys
- add_default_name_and_id(html_options)
- value = value(object)
- content_tag("select",
- add_options(
- time_zone_options_for_select(value || options[:default], priority_zones, options[:model] || ActiveSupport::TimeZone),
- options, value
- ), html_options
+ select_content_tag(
+ time_zone_options_for_select(value(object) || options[:default], priority_zones, options[:model] || ActiveSupport::TimeZone), options, html_options
)
end
@@ -603,6 +608,17 @@ module ActionView
end
option_tags.html_safe
end
+
+ def select_content_tag(option_tags, options, html_options)
+ html_options = html_options.stringify_keys
+ add_default_name_and_id(html_options)
+ select = content_tag("select", add_options(option_tags, options, value(object)), html_options)
+ if html_options["multiple"]
+ tag("input", :disabled => html_options["disabled"], :name => html_options["name"], :type => "hidden", :value => "") + select
+ else
+ select
+ end
+ end
end
class FormBuilder
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index a91e86f4db..72bc4510b5 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -597,6 +597,12 @@ module ActionView
number_field_tag(name, value, options.stringify_keys.update("type" => "range"))
end
+ # Creates the hidden UTF8 enforcer tag. Override this method in a helper
+ # to customize the tag.
+ def utf8_enforcer_tag
+ tag(:input, :type => "hidden", :name => "utf8", :value => "&#x2713;".html_safe)
+ end
+
private
def html_options_for_form(url_for_options, options, *parameters_for_url)
options.stringify_keys.tap do |html_options|
@@ -611,9 +617,6 @@ module ActionView
end
def extra_tags_for_form(html_options)
- snowman_tag = tag(:input, :type => "hidden",
- :name => "utf8", :value => "&#x2713;".html_safe)
-
authenticity_token = html_options.delete("authenticity_token")
method = html_options.delete("method").to_s
@@ -629,7 +632,7 @@ module ActionView
tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag(authenticity_token)
end
- tags = snowman_tag << method_tag
+ tags = utf8_enforcer_tag << method_tag
content_tag(:div, tags, :style => 'margin:0;padding:0;display:inline')
end
diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb
index d7228bab67..4484390fde 100644
--- a/actionpack/lib/action_view/helpers/javascript_helper.rb
+++ b/actionpack/lib/action_view/helpers/javascript_helper.rb
@@ -18,7 +18,8 @@ module ActionView
# $('some_element').replaceWith('<%=j render 'some/element_template' %>');
def escape_javascript(javascript)
if javascript
- javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
+ result = javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) {|match| JS_ESCAPE_MAP[match] }
+ javascript.html_safe? ? result.html_safe : result
else
''
end
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 63d13a0f0b..fe0288521f 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -211,7 +211,7 @@ module ActionView
defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
options = options.reverse_merge(defaults)
- parts = number.to_s.split('.')
+ parts = number.to_s.to_str.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
parts.join(options[:separator]).html_safe
@@ -342,7 +342,7 @@ module ActionView
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
-
+
base = options[:prefix] == :si ? 1000 : 1024
if number.to_i < base
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 75422a343d..ae71ade588 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -255,9 +255,11 @@ module ActionView
# simple_format("<span>I'm allowed!</span> It's true.", {}, :sanitize => false)
# # => "<p><span>I'm allowed!</span> It's true.</p>"
def simple_format(text, html_options={}, options={})
- text = ''.html_safe if text.nil?
+ text = '' if text.nil?
+ text = text.dup if text.frozen?
start_tag = tag('p', html_options, true)
text = sanitize(text) unless options[:sanitize] == false
+ text = text.to_str
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
@@ -279,7 +281,7 @@ module ActionView
# @items = [1,2,3,4]
# <table>
# <% @items.each do |item| %>
- # <tr class="<%= cycle("even", "odd") -%>">
+ # <tr class="<%= cycle("odd", "even") -%>">
# <td>item</td>
# </tr>
# <% end %>
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index fd8fe417d0..26b6e8b599 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -5,7 +5,7 @@ module I18n
class ExceptionHandler
include Module.new {
def call(exception, locale, key, options)
- exception.is_a?(MissingTranslation) ? super.html_safe : super
+ exception.is_a?(MissingTranslation) && options[:rescue_format] == :html ? super.html_safe : super
end
}
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 25411856cb..d70ae4196b 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -55,9 +55,9 @@ module ActionView
#
# ==== Relying on named routes
#
- # If you instead of a hash pass a record (like an Active Record or Active Resource) as the options parameter,
- # you'll trigger the named route for that record. The lookup will happen on the name of the class. So passing
- # a Workshop object will attempt to use the +workshop_path+ route. If you have a nested route, such as
+ # Passing a record (like an Active Record or Active Resource) instead of a Hash as the options parameter will
+ # trigger the named route for that record. The lookup will happen on the name of the class. So passing a
+ # Workshop object will attempt to use the +workshop_path+ route. If you have a nested route, such as
# +admin_workshop_path+ you'll have to call that explicitly (it's impossible for +url_for+ to guess that route).
#
# ==== Examples
@@ -112,13 +112,13 @@ module ActionView
end
end
- # Creates a link tag of the given +name+ using a URL created by the set
- # of +options+. See the valid options in the documentation for
- # +url_for+. It's also possible to pass a string instead
- # of an options hash to get a link tag that uses the value of the string as the
- # href for the link, or use <tt>:back</tt> to link to the referrer - a JavaScript back
- # link will be used in place of a referrer if none exists. If +nil+ is passed as
- # a name, the link itself will become the name.
+ # Creates a link tag of the given +name+ using a URL created by the set of +options+.
+ # See the valid options in the documentation for +url_for+. It's also possible to
+ # pass a String instead of an options hash, which generates a link tag that uses the
+ # value of the String as the href for the link. Using a <tt>:back</tt> Symbol instead
+ # of an options hash will generate a link to the referrer (a JavaScript back link
+ # will be used in place of a referrer if none exists). If +nil+ is passed as the name
+ # the value of the link itself will become the name.
#
# ==== Signatures
#
@@ -497,14 +497,14 @@ module ActionView
}.compact
extras = extras.empty? ? '' : '?' + ERB::Util.html_escape(extras.join('&'))
- email_address_obfuscated = email_address.dup
+ email_address_obfuscated = email_address.to_str
email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.key?("replace_at")
email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.key?("replace_dot")
case encode
when "javascript"
string = ''
html = content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe))
- html = escape_javascript(html)
+ html = escape_javascript(html.to_str)
"document.write('#{html}');".each_byte do |c|
string << sprintf("%%%x", c)
end
@@ -619,7 +619,9 @@ module ActionView
end
def add_method_to_attributes!(html_options, method)
- html_options["rel"] = "nofollow" if method.to_s.downcase != "get"
+ if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
+ html_options["rel"] = "#{html_options["rel"]} nofollow".strip
+ end
html_options["data-method"] = method
end
diff --git a/actionpack/lib/action_view/log_subscriber.rb b/actionpack/lib/action_view/log_subscriber.rb
index 29ffbd6fdd..bf90d012bf 100644
--- a/actionpack/lib/action_view/log_subscriber.rb
+++ b/actionpack/lib/action_view/log_subscriber.rb
@@ -4,7 +4,7 @@ module ActionView
# Provides functionality so that Rails can output logs from Action View.
class LogSubscriber < ActiveSupport::LogSubscriber
def render_template(event)
- message = "Rendered #{from_rails_root(event.payload[:identifier])}"
+ message = " Rendered #{from_rails_root(event.payload[:identifier])}"
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
message << (" (%.1fms)" % event.duration)
info(message)
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index f0ed3425de..560df15e82 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -10,7 +10,7 @@ module ActionView
# this key is generated just once during the request, it speeds up all cache accesses.
class LookupContext #:nodoc:
attr_accessor :prefixes
-
+
mattr_accessor :fallbacks
@@fallbacks = FallbackFileSystemResolver.instances
diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb
index a09cef8fef..d04c00fd40 100644
--- a/actionpack/lib/action_view/renderer/template_renderer.rb
+++ b/actionpack/lib/action_view/renderer/template_renderer.rb
@@ -64,7 +64,7 @@ module ActionView
layout =~ /^\// ?
with_fallbacks { find_template(layout, nil, false, keys) } : find_template(layout, nil, false, keys)
end
- rescue ActionView::MissingTemplate => e
+ rescue ActionView::MissingTemplate
update_details(:formats => nil) do
raise unless template_exists?(layout)
end
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index d4448a7b33..587e37a84f 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -31,7 +31,6 @@ 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"
elsif path =~ /layouts/i
diff --git a/actionpack/lib/action_view/testing/resolvers.rb b/actionpack/lib/action_view/testing/resolvers.rb
index 773dfcbb1d..7afa2fa613 100644
--- a/actionpack/lib/action_view/testing/resolvers.rb
+++ b/actionpack/lib/action_view/testing/resolvers.rb
@@ -34,7 +34,7 @@ module ActionView #:nodoc:
templates << Template.new(source, _path, handler,
:virtual_path => path.virtual, :format => format, :updated_at => updated_at)
end
-
+
templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
end
end
diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb
index a99dcad81d..9f1f0f3b68 100644
--- a/actionpack/lib/sprockets/helpers/rails_helper.rb
+++ b/actionpack/lib/sprockets/helpers/rails_helper.rb
@@ -1,5 +1,4 @@
-require "action_view/helpers/asset_paths"
-require "action_view/helpers/asset_tag_helper"
+require "action_view/helpers"
module Sprockets
module Helpers
@@ -15,42 +14,48 @@ module Sprockets
end
end
- def javascript_include_tag(source, options = {})
+ def javascript_include_tag(*sources)
+ options = sources.extract_options!
debug = options.key?(:debug) ? options.delete(:debug) : debug_assets?
body = options.key?(:body) ? options.delete(:body) : false
- if debug && asset = asset_paths.asset_for(source, 'js')
- asset.to_a.map { |dep|
- javascript_include_tag(dep, :debug => false, :body => true)
- }.join("\n").html_safe
- else
- options = {
- 'type' => "text/javascript",
- 'src' => asset_path(source, 'js', body)
- }.merge(options.stringify_keys)
-
- content_tag 'script', "", options
- end
+ sources.collect do |source|
+ if debug && asset = asset_paths.asset_for(source, 'js')
+ asset.to_a.map { |dep|
+ javascript_include_tag(dep, :debug => false, :body => true)
+ }.join("\n").html_safe
+ else
+ tag_options = {
+ 'type' => "text/javascript",
+ 'src' => asset_path(source, 'js', body)
+ }.merge(options.stringify_keys)
+
+ content_tag 'script', "", tag_options
+ end
+ end.join("\n").html_safe
end
- def stylesheet_link_tag(source, options = {})
+ def stylesheet_link_tag(*sources)
+ options = sources.extract_options!
debug = options.key?(:debug) ? options.delete(:debug) : debug_assets?
body = options.key?(:body) ? options.delete(:body) : false
- if debug && asset = asset_paths.asset_for(source, 'css')
- asset.to_a.map { |dep|
- stylesheet_link_tag(dep, :debug => false, :body => true)
- }.join("\n").html_safe
- else
- options = {
- 'rel' => "stylesheet",
- 'type' => "text/css",
- 'media' => "screen",
- 'href' => asset_path(source, 'css', body)
- }.merge(options.stringify_keys)
-
- tag 'link', options
- end
+ sources.collect do |source|
+ if debug && asset = asset_paths.asset_for(source, 'css')
+ asset.to_a.map { |dep|
+ stylesheet_link_tag(dep, :debug => false, :body => true)
+ }.join("\n").html_safe
+ else
+ tag_options = {
+ 'rel' => "stylesheet",
+ 'type' => "text/css",
+ 'media' => "screen",
+ 'href' => asset_path(source, 'css', body)
+ }.merge(options.stringify_keys)
+
+ tag 'link', tag_options
+ end
+ end.join("\n").html_safe
end
private
@@ -61,13 +66,13 @@ module Sprockets
def asset_path(source, default_ext = nil, body = false)
source = source.logical_path if source.respond_to?(:logical_path)
- path = asset_paths.compute_public_path(source, 'assets', default_ext, true)
+ path = asset_paths.compute_public_path(source, Rails.application.config.assets.prefix, default_ext, true)
body ? "#{path}?body=1" : path
end
- class AssetPaths < ActionView::Helpers::AssetPaths #:nodoc:
+ class AssetPaths < ::ActionView::AssetPaths #:nodoc:
def compute_public_path(source, dir, ext=nil, include_host=true)
- super(source, 'assets', ext, include_host)
+ super(source, Rails.application.config.assets.prefix, ext, include_host)
end
def asset_for(source, ext)
diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb
index 7b8a7ad3bb..ab5101f6fc 100644
--- a/actionpack/lib/sprockets/railtie.rb
+++ b/actionpack/lib/sprockets/railtie.rb
@@ -46,43 +46,61 @@ module Sprockets
end
protected
+ def asset_environment(app)
+ require "sprockets"
- def asset_environment(app)
- require "sprockets"
- assets = app.config.assets
- env = Sprockets::Environment.new(app.root.to_s)
- env.static_root = File.join(app.root.join("public"), assets.prefix)
- env.paths.concat assets.paths
- env.logger = Rails.logger
- env.js_compressor = expand_js_compressor(assets.js_compressor) if assets.compress
- env.css_compressor = expand_css_compressor(assets.css_compressor) if assets.compress
- env
- end
+ assets = app.config.assets
+
+ env = Sprockets::Environment.new(app.root.to_s)
+
+ env.static_root = File.join(app.root.join("public"), assets.prefix)
+
+ if env.respond_to?(:append_path)
+ assets.paths.each { |path| env.append_path(path) }
+ else
+ env.paths.concat assets.paths
+ end
+
+ env.logger = Rails.logger
+
+ if env.respond_to?(:cache)
+ env.cache = Rails.cache
+ end
- def expand_js_compressor(sym)
- case sym
- when :closure
- require 'closure-compiler'
- Closure::Compiler.new
- when :uglifier
- require 'uglifier'
- Uglifier.new
- when :yui
- require 'yui/compressor'
- YUI::JavaScriptCompressor.new
- else
- sym
+ if assets.compress
+ # temporarily hardcode default JS compressor to uglify. Soon, it will work
+ # the same as SCSS, where a default plugin sets the default.
+ env.js_compressor = expand_js_compressor(assets.js_compressor || :uglifier)
+ env.css_compressor = expand_css_compressor(assets.css_compressor)
+ end
+
+ env
+ end
+
+ def expand_js_compressor(sym)
+ case sym
+ when :closure
+ require 'closure-compiler'
+ Closure::Compiler.new
+ when :uglifier
+ require 'uglifier'
+ Uglifier.new
+ when :yui
+ require 'yui/compressor'
+ YUI::JavaScriptCompressor.new
+ else
+ sym
+ end
end
- end
- def expand_css_compressor(sym)
- case sym
- when :yui
- require 'yui/compressor'
- YUI::CssCompressor.new
- else
- sym
+ def expand_css_compressor(sym)
+ case sym
+ when :yui
+ require 'yui/compressor'
+ YUI::CssCompressor.new
+ else
+ sym
+ end
end
- end
end
end