aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_view/helpers')
-rw-r--r--actionpack/lib/action_view/helpers/asset_paths.rb75
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb23
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb15
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb11
-rw-r--r--actionpack/lib/action_view/helpers/atom_feed_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/controller_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb15
-rw-r--r--actionpack/lib/action_view/helpers/debug_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb47
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb78
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb13
-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/sanitize_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb40
21 files changed, 158 insertions, 214 deletions
diff --git a/actionpack/lib/action_view/helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_paths.rb
index 1bc5c9e003..fae2e4fc1c 100644
--- a/actionpack/lib/action_view/helpers/asset_paths.rb
+++ b/actionpack/lib/action_view/helpers/asset_paths.rb
@@ -1,78 +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_host_and_protocol(source, 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 \ No newline at end of file
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 7970176d37..509c29844a 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -1,6 +1,7 @@
require 'action_view/helpers/asset_tag_helpers/javascript_tag_helpers'
require 'action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers'
require 'action_view/helpers/asset_tag_helpers/asset_paths'
+require 'action_view/helpers/tag_helper'
module ActionView
# = Action View Asset Tag Helpers
@@ -191,6 +192,7 @@ module ActionView
# RewriteEngine On
# RewriteRule ^/release-\d+/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L]
module AssetTagHelper
+ include TagHelper
include JavascriptTagHelpers
include StylesheetTagHelpers
# Returns a link tag that browsers and news readers can use to auto-detect
@@ -347,7 +349,7 @@ module ActionView
src = options[:src] = path_to_image(source)
unless src =~ /^cid:/
- options[:alt] = options.fetch(:alt){ File.basename(src, '.*').capitalize }
+ options[:alt] = options.fetch(:alt){ image_alt(src) }
end
if size = options.delete(:size)
@@ -362,6 +364,10 @@ module ActionView
tag("img", options)
end
+ def image_alt(src)
+ File.basename(src, '.*').sub(/-[[:xdigit:]]{32}\z/, '').capitalize
+ end
+
# Returns an html video tag for the +sources+. If +sources+ is a string,
# a single video tag will be returned. If +sources+ is an array, a video
# tag with nested source tags for each source will be returned. The
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
index e4662a2919..3c05173a1b 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb
@@ -60,12 +60,16 @@ module ActionView
private
- def path_to_asset(source, include_host = true)
- asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, include_host)
+ def path_to_asset(source, include_host = true, protocol = nil)
+ asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, include_host, protocol)
+ end
+
+ def path_to_asset_source(source)
+ asset_paths.compute_source_path(source, asset_name.to_s.pluralize, extension)
end
def compute_paths(*args)
- expand_sources(*args).collect { |source| asset_paths.compute_public_path(source, asset_name.pluralize, extension, false) }
+ expand_sources(*args).collect { |source| path_to_asset_source(source) }
end
def expand_sources(sources, recursive)
@@ -92,7 +96,7 @@ module ActionView
def ensure_sources!(sources)
sources.each do |source|
- asset_file_path!(path_to_asset(source, false))
+ asset_file_path!(path_to_asset_source(source))
end
end
@@ -123,19 +127,14 @@ module ActionView
# Set mtime to the latest of the combined files to allow for
# consistent ETag without a shared filesystem.
- mt = asset_paths.map { |p| File.mtime(asset_file_path(p)) }.max
+ mt = asset_paths.map { |p| File.mtime(asset_file_path!(p)) }.max
File.utime(mt, mt, joined_asset_path)
end
- def asset_file_path(path)
- File.join(config.assets_dir, path.split('?').first)
- end
-
- def asset_file_path!(path, error_if_file_is_uri = false)
- if asset_paths.is_uri?(path)
+ def asset_file_path!(absolute_path, error_if_file_is_uri = false)
+ if asset_paths.is_uri?(absolute_path)
raise(Errno::ENOENT, "Asset file #{path} is uri and cannot be merged into single file") if error_if_file_is_uri
else
- absolute_path = asset_file_path(path)
raise(Errno::ENOENT, "Asset file not found at '#{absolute_path}'" ) unless File.exist?(absolute_path)
return absolute_path
end
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 cd0f8c8878..8b35aa8896 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,11 @@
+require 'thread'
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
@@ -85,17 +85,8 @@ module ActionView
end
end
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
- super(source, has_request)
- end
end
end
end
-end \ No newline at end of file
+end
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 e4f11c9bc7..8c25d38bbd 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
@@ -16,7 +16,8 @@ module ActionView
end
def asset_tag(source, options)
- tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source)) }.merge(options), false, false)
+ # We force the :request protocol here to avoid a double-download bug in IE7 and IE8
+ tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source, true, :request)) }.merge(options), false, false)
end
def custom_dir
@@ -52,7 +53,7 @@ module ActionView
# If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs).
# Full paths from the document root will be passed through.
# Used internally by +stylesheet_link_tag+ to build the stylesheet path.
- #
+ #
# ==== Examples
# stylesheet_path "style" # => /stylesheets/style.css
# stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
@@ -60,11 +61,7 @@ module ActionView
# stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
# stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
def stylesheet_path(source)
- if config.use_sprockets
- asset_path(source, 'css')
- else
- asset_paths.compute_public_path(source, 'stylesheets', 'css')
- end
+ asset_paths.compute_public_path(source, 'stylesheets', 'css', true, :request)
end
alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route
diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
index a087688a2c..39c37b25dc 100644
--- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
@@ -20,7 +20,7 @@ module ActionView
# # GET /posts.html
# # GET /posts.atom
# def index
- # @posts = Post.find(:all)
+ # @posts = Post.all
#
# respond_to do |format|
# format.html
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/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index 3b5f4e694f..62f95379cd 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -27,7 +27,7 @@ module ActionView
# "The current timestamp is #{Time.now}."
# end
#
- # You can then use that variable anywhere else. For example:
+ # You can then use that variable anywhere else. For example:
#
# <html>
# <head><title><%= @greeting %></title></head>
@@ -76,7 +76,7 @@ module ActionView
#
# <%= stored_content %>
#
- # You can use the <tt>yield</tt> syntax alongside an existing call to <tt>yield</tt> in a layout. For example:
+ # You can use the <tt>yield</tt> syntax alongside an existing call to <tt>yield</tt> in a layout. For example:
#
# <%# This is the layout %>
# <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
diff --git a/actionpack/lib/action_view/helpers/controller_helper.rb b/actionpack/lib/action_view/helpers/controller_helper.rb
index e22331cb3c..1a583e62ae 100644
--- a/actionpack/lib/action_view/helpers/controller_helper.rb
+++ b/actionpack/lib/action_view/helpers/controller_helper.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/module/attr_internal'
+
module ActionView
module Helpers
# This module keeps all methods and behavior in ActionView
@@ -18,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 c78c03a5eb..6a724749f4 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -517,7 +517,7 @@ module ActionView
# # that is named 'due' rather than 'day'.
# select_day(my_time, :field_name => 'due')
#
- # # Generates a select field for days with a custom prompt. Use <tt>:prompt => true</tt> for a
+ # # Generates a select field for days with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_day(5, :prompt => 'Choose day')
#
@@ -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..3a30263b49 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -4,6 +4,7 @@ require 'action_view/helpers/tag_helper'
require 'action_view/helpers/form_tag_helper'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/hash/slice'
+require 'active_support/core_ext/module/method_names'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/output_safety'
require 'active_support/core_ext/array/extract_options'
@@ -202,13 +203,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 +220,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 +291,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 +518,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:
@@ -555,19 +568,6 @@ module ActionView
# ...
# <% end %>
#
- # In addition, you may want to have access to the current iteration index.
- # In that case, you can use a similar method called fields_for_with_index
- # which receives a block with an extra parameter:
- #
- # <%= form_for @person do |person_form| %>
- # ...
- # <%= person_form.fields_for_with_index :projects do |project_fields, index| %>
- # Position: <%= index %>
- # Name: <%= project_fields.text_field :name %>
- # <% end %>
- # ...
- # <% end %>
- #
# When projects is already an association on Person you can use
# +accepts_nested_attributes_for+ to define the writer method for you:
#
@@ -1149,7 +1149,7 @@ module ActionView
options["name"] ||= tag_name_with_index(@auto_index)
options["id"] = options.fetch("id"){ tag_id_with_index(@auto_index) }
else
- options["name"] ||= tag_name + (options.has_key?('multiple') ? '[]' : '')
+ options["name"] ||= tag_name + (options['multiple'] ? '[]' : '')
options["id"] = options.fetch("id"){ tag_id }
end
end
@@ -1229,15 +1229,8 @@ module ActionView
RUBY_EVAL
end
- # Check +fields_for+ for docs and examples.
- def fields_for_with_index(record_name, record_object = nil, fields_options = {}, &block)
- index = fields_options[:index] || options[:child_index] || nested_child_index(@object_name)
- block_with_index = Proc.new{ |obj| block.call(obj, index) }
- fields_for(record_name, record_object, fields_options, &block_with_index)
- 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 0aaa690129..3dc6d65432 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -125,9 +125,31 @@ module ActionView
# This allows the user to submit a form page more than once with the expected results of creating multiple records.
# In addition, this allows a single partial to be used to generate form inputs for both edit and create forms.
#
- # By default, <tt>post.person_id</tt> is the selected option. Specify <tt>:selected => value</tt> to use a different selection
+ # 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
@@ -255,7 +277,7 @@ module ActionView
# Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
# where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
# the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
- # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +selected+
+ # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +selected+
# may also be an array of values to be selected when using a multiple select.
#
# Examples (call, result):
@@ -406,13 +428,13 @@ module ActionView
# wraps them with <tt><optgroup></tt> tags.
#
# Parameters:
- # * +grouped_options+ - Accepts a nested array or hash of strings. The first value serves as the
+ # * +grouped_options+ - Accepts a nested array or hash of strings. The first value serves as the
# <tt><optgroup></tt> label while the second value must be an array of options. The second value can be a
# nested array of text-value pairs. See <tt>options_for_select</tt> for more info.
# Ex. ["North America",[["United States","US"],["Canada","CA"]]]
# * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
# which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
- # as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
+ # as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
# * +prompt+ - set to true or a prompt string. When the select element doesn't have a value yet, this
# prepends an option with a generic prompt - "Please select" - or the given prompt string.
#
@@ -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 65a98fb27a..72bc4510b5 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -204,7 +204,7 @@ module ActionView
text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
end
- # Creates a file upload field. If you are using file uploads then you will also need
+ # Creates a file upload field. If you are using file uploads then you will also need
# to set the multipart option for the form tag:
#
# <%= form_tag '/upload', :multipart => true do %>
@@ -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/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index 841be0a567..bcc8f6fbcb 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -14,13 +14,13 @@ module ActionView
#
# It also strips href/src tags with invalid protocols, like javascript: especially.
# It does its best to counter any tricks that hackers may use, like throwing in
- # unicode/ascii/hex values to get past the javascript: filters. Check out
+ # unicode/ascii/hex values to get past the javascript: filters. Check out
# the extensive test suite.
#
# <%= sanitize @article.body %>
#
# You can add or remove tags/attributes if you want to customize it a bit.
- # See ActionView::Base for full docs on the available options. You can add
+ # See ActionView::Base for full docs on the available options. You can add
# tags/attributes for single uses of +sanitize+ by passing either the
# <tt>:attributes</tt> or <tt>:tags</tt> options:
#
@@ -66,7 +66,7 @@ module ActionView
self.class.white_list_sanitizer.sanitize_css(style)
end
- # Strips all HTML tags from the +html+, including comments. This uses the
+ # Strips all HTML tags from the +html+, including comments. This uses the
# html-scanner tokenizer and so its HTML parsing ability is limited by
# that of html-scanner.
#
@@ -142,7 +142,7 @@ module ActionView
white_list_sanitizer.protocol_separator = value
end
- # Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with
+ # Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with
# any object that responds to +sanitize+.
#
# class Application < Rails::Application
@@ -153,7 +153,7 @@ module ActionView
@full_sanitizer ||= HTML::FullSanitizer.new
end
- # Gets the HTML::LinkSanitizer instance used by +strip_links+. Replace with
+ # Gets the HTML::LinkSanitizer instance used by +strip_links+. Replace with
# any object that responds to +sanitize+.
#
# class Application < Rails::Application
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index 786af5ca58..8c33ef09fa 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -94,7 +94,7 @@ module ActionView
end
end
- # Returns a CDATA section with the given +content+. CDATA sections
+ # Returns a CDATA section with the given +content+. CDATA sections
# are used to escape blocks of text containing characters which would
# otherwise be recognized as markup. CDATA sections begin with the string
# <tt><![CDATA[</tt> and end with (and may not contain) the string <tt>]]></tt>.
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index ca09c77b5c..ae71ade588 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -232,7 +232,7 @@ module ActionView
# considered as a linebreak and a <tt><br /></tt> tag is appended. This
# method does not remove the newlines from the +text+.
#
- # You can pass any HTML attributes into <tt>html_options</tt>. These
+ # You can pass any HTML attributes into <tt>html_options</tt>. These
# will be added to all created paragraphs.
#
# ==== Options
@@ -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
@@ -267,7 +269,7 @@ module ActionView
# Creates a Cycle object whose _to_s_ method cycles through elements of an
# array every time it is called. This can be used for example, to alternate
- # classes for table rows. You can use named cycles to allow nesting in loops.
+ # classes for table rows. You can use named cycles to allow nesting in loops.
# Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
# named cycle. The default name for a cycle without a +:name+ key is
# <tt>"default"</tt>. You can manually reset a cycle by calling reset_cycle
@@ -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 5488c752cc..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
#
@@ -160,7 +160,7 @@ module ActionView
#
# ==== Examples
# Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
- # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
+ # and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
# your application on resources and use
#
# link_to "Profile", profile_path(@profile)
@@ -348,7 +348,7 @@ module ActionView
# Creates a link tag of the given +name+ using a URL created by the set of
# +options+ unless the current request URI is the same as the links, in
# which case only the name is returned (or the given block is yielded, if
- # one exists). You can give +link_to_unless_current+ a block which will
+ # one exists). You can give +link_to_unless_current+ a block which will
# specialize the default behavior (e.g., show a "Start Here" link rather
# than the link's text).
#
@@ -375,7 +375,7 @@ module ActionView
# </ul>
#
# The implicit block given to +link_to_unless_current+ is evaluated if the current
- # action is the action given. So, if we had a comments page and wanted to render a
+ # action is the action given. So, if we had a comments page and wanted to render a
# "Go Back" link instead of a link to the comments page, we could do something like this...
#
# <%=
@@ -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
@@ -579,7 +579,7 @@ module ActionView
url_string = url_for(options)
# We ignore any extra parameters in the request_uri if the
- # submitted url doesn't have any either. This lets the function
+ # submitted url doesn't have any either. This lets the function
# work with things like ?order=asc
if url_string.index("?")
request_uri = request.fullpath
@@ -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
@@ -641,7 +643,7 @@ module ActionView
# Processes the +html_options+ hash, converting the boolean
# attributes from true/false form into the form required by
- # HTML/XHTML. (An attribute is considered to be boolean if
+ # HTML/XHTML. (An attribute is considered to be boolean if
# its name is listed in the given +bool_attrs+ array.)
#
# More specifically, for each boolean attribute in +html_options+
@@ -651,7 +653,7 @@ module ActionView
#
# if the associated +bool_value+ evaluates to true, it is
# replaced with the attribute's name; otherwise the attribute is
- # removed from the +html_options+ hash. (See the XHTML 1.0 spec,
+ # removed from the +html_options+ hash. (See the XHTML 1.0 spec,
# section 4.5 "Attribute Minimization" for more:
# http://www.w3.org/TR/xhtml1/#h-4.5)
#