aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb36
-rw-r--r--actionpack/test/template/erb_util_test.rb14
-rw-r--r--actionpack/test/template/url_helper_test.rb16
-rw-r--r--activemodel/lib/active_model/errors.rb2
-rw-r--r--activemodel/lib/active_model/validations/validates.rb13
-rw-r--r--activemodel/test/cases/validations_test.rb15
-rw-r--r--activesupport/CHANGELOG.md2
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb19
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb5
-rw-r--r--activesupport/test/multibyte_chars_test.rb3
11 files changed, 83 insertions, 44 deletions
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index d7a2651bad..ecd26891d6 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -118,7 +118,7 @@ module ActionView
# escape_once("<< Accept & Checkout")
# # => "<< Accept & Checkout"
def escape_once(html)
- html.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
+ ERB::Util.html_escape_once(html)
end
private
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index d27d49821b..b5fc882e31 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -323,30 +323,24 @@ module ActionView
# #
def button_to(name, options = {}, html_options = {})
html_options = html_options.stringify_keys
- convert_boolean_attributes!(html_options, %w( disabled ))
+ convert_boolean_attributes!(html_options, %w(disabled))
- method_tag = ''
- if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
- method_tag = method_tag(method)
- end
+ url = options.is_a?(String) ? options : url_for(options)
+ remote = html_options.delete('remote')
- form_method = method.to_s == 'get' ? 'get' : 'post'
+ method = html_options.delete('method').to_s
+ method_tag = %w{put delete}.include?(method) ? method_tag(method) : ""
+
+ form_method = method == 'get' ? 'get' : 'post'
form_options = html_options.delete('form') || {}
form_options[:class] ||= html_options.delete('form_class') || 'button_to'
-
- remote = html_options.delete('remote')
+ form_options.merge!(:method => form_method, :action => url)
+ form_options.merge!("data-remote" => "true") if remote
request_token_tag = form_method == 'post' ? token_tag : ''
- url = options.is_a?(String) ? options : self.url_for(options)
- name ||= url
-
html_options = convert_options_to_data_attributes(options, html_options)
-
- html_options.merge!("type" => "submit", "value" => name)
-
- form_options.merge!(:method => form_method, :action => url)
- form_options.merge!("data-remote" => "true") if remote
+ html_options.merge!("type" => "submit", "value" => name || url)
"#{tag(:form, form_options, true)}<div>#{method_tag}#{tag("input", html_options)}#{request_token_tag}</div></form>".html_safe
end
@@ -596,11 +590,7 @@ module ActionView
# We ignore any extra parameters in the request_uri if the
# 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
- else
- request_uri = request.path
- end
+ request_uri = url_string.index("?") ? request.fullpath : request.path
if url_string =~ /^\w+:\/\//
url_string == "#{request.protocol}#{request.host_with_port}#{request_uri}"
@@ -630,12 +620,12 @@ module ActionView
end
def link_to_remote_options?(options)
- options.is_a?(Hash) && options.key?('remote') && options.delete('remote')
+ options.is_a?(Hash) && options.delete('remote')
end
def add_method_to_attributes!(html_options, method)
if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
- html_options["rel"] = "#{html_options["rel"]} nofollow".strip
+ html_options["rel"] = "#{html_options["rel"]} nofollow".lstrip
end
html_options["data-method"] = method
end
diff --git a/actionpack/test/template/erb_util_test.rb b/actionpack/test/template/erb_util_test.rb
index eba2ef64e0..ca2710e9b3 100644
--- a/actionpack/test/template/erb_util_test.rb
+++ b/actionpack/test/template/erb_util_test.rb
@@ -44,4 +44,18 @@ class ErbUtilTest < ActiveSupport::TestCase
assert_equal chr, html_escape(chr)
end
end
+
+ def test_html_escape_once
+ assert_equal '1 &lt; 2 &amp; 3', html_escape_once('1 < 2 &amp; 3')
+ end
+
+ def test_html_escape_once_returns_unsafe_strings_when_passed_unsafe_strings
+ value = html_escape_once('1 < 2 &amp; 3')
+ assert !value.html_safe?
+ end
+
+ def test_html_escape_once_returns_safe_strings_when_passed_safe_strings
+ value = html_escape_once('1 < 2 &amp; 3'.html_safe)
+ assert value.html_safe?
+ end
end
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index cf4dafbac4..37ec0e323d 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -31,13 +31,13 @@ class UrlHelperTest < ActiveSupport::TestCase
setup :_prepare_context
- def hash_for(opts = [])
- ActiveSupport::OrderedHash[*([:controller, "foo", :action, "bar"].concat(opts))]
+ def hash_for(options = {})
+ { :controller => "foo", :action => "bar" }.merge!(options)
end
alias url_hash hash_for
def test_url_for_does_not_escape_urls
- assert_equal "/?a=b&c=d", url_for(hash_for([:a, :b, :c, :d]))
+ assert_equal "/?a=b&c=d", url_for(hash_for(:a => :b, :c => :d))
end
def test_url_for_with_back
@@ -168,7 +168,7 @@ class UrlHelperTest < ActiveSupport::TestCase
end
def test_link_tag_with_host_option
- hash = hash_for([:host, "www.example.com"])
+ hash = hash_for(:host => "www.example.com")
expected = %q{<a href="http://www.example.com/">Test Link</a>}
assert_dom_equal(expected, link_to('Test Link', hash))
end
@@ -343,7 +343,7 @@ class UrlHelperTest < ActiveSupport::TestCase
def test_current_page_with_params_that_match
@request = request_for_url("/?order=desc&page=1")
- assert current_page?(hash_for([:order, "desc", :page, "1"]))
+ assert current_page?(hash_for(:order => "desc", :page => "1"))
assert current_page?("http://www.example.com/?order=desc&page=1")
end
@@ -371,20 +371,20 @@ class UrlHelperTest < ActiveSupport::TestCase
@request = request_for_url("/?order=desc&page=1")
assert_equal "Showing",
- link_to_unless_current("Showing", hash_for([:order, 'desc', :page, '1']))
+ link_to_unless_current("Showing", hash_for(:order => 'desc', :page => '1'))
assert_equal "Showing",
link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=1")
@request = request_for_url("/?order=desc")
assert_equal %{<a href="/?order=asc">Showing</a>},
- link_to_unless_current("Showing", hash_for([:order, :asc]))
+ link_to_unless_current("Showing", hash_for(:order => :asc))
assert_equal %{<a href="http://www.example.com/?order=asc">Showing</a>},
link_to_unless_current("Showing", "http://www.example.com/?order=asc")
@request = request_for_url("/?order=desc")
assert_equal %{<a href="/?order=desc&amp;page=2\">Showing</a>},
- link_to_unless_current("Showing", hash_for([:order, "desc", :page, 2]))
+ link_to_unless_current("Showing", hash_for(:order => "desc", :page => 2))
assert_equal %{<a href="http://www.example.com/?order=desc&amp;page=2">Showing</a>},
link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=2")
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 023c872055..75feba1fe7 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -224,7 +224,7 @@ module ActiveModel
def add(attribute, message = nil, options = {})
message = normalize_message(attribute, message, options)
if options[:strict]
- raise ActiveModel::StrictValidationFailed, message
+ raise ActiveModel::StrictValidationFailed, full_message(attribute, message)
end
self[attribute] << message
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index 3713fc828e..9bb72d6631 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -1,7 +1,6 @@
require 'active_support/core_ext/hash/slice'
module ActiveModel
-
# == Active Model validates method
module Validations
module ClassMethods
@@ -101,11 +100,11 @@ module ActiveModel
end
end
- # This method is used to define validation that can not be corrected by end user
- # and is considered exceptional.
- # So each validator defined with bang or <tt>:strict</tt> option set to <tt>true</tt>
- # will always raise <tt>ActiveModel::InternalValidationFailed</tt> instead of adding error
- # when validation fails
+ # This method is used to define validation that cannot be corrected by end
+ # user and is considered exceptional. So each validator defined with bang
+ # or <tt>:strict</tt> option set to <tt>true</tt> will always raise
+ # <tt>ActiveModel::StrictValidationFailed</tt> instead of adding error
+ # when validation fails.
# See <tt>validates</tt> for more information about validation itself.
def validates!(*attributes)
options = attributes.extract_options!
@@ -118,7 +117,7 @@ module ActiveModel
# When creating custom validators, it might be useful to be able to specify
# additional default keys. This can be done by overwriting this method.
def _validates_default_keys
- [ :if, :unless, :on, :allow_blank, :allow_nil , :strict]
+ [:if, :unless, :on, :allow_blank, :allow_nil , :strict]
end
def _parse_validates_options(options) #:nodoc:
diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb
index fe5358a9d0..0b1de62a48 100644
--- a/activemodel/test/cases/validations_test.rb
+++ b/activemodel/test/cases/validations_test.rb
@@ -310,7 +310,7 @@ class ValidationsTest < ActiveModel::TestCase
end
def test_strict_validation_particular_validator
- Topic.validates :title, :presence => {:strict => true}
+ Topic.validates :title, :presence => { :strict => true }
assert_raises ActiveModel::StrictValidationFailed do
Topic.new.valid?
end
@@ -330,9 +330,18 @@ class ValidationsTest < ActiveModel::TestCase
end
end
+ def test_strict_validation_error_message
+ Topic.validates :title, :strict => true, :presence => true
+
+ exception = assert_raises(ActiveModel::StrictValidationFailed) do
+ Topic.new.valid?
+ end
+ assert_equal "Title can't be blank", exception.message
+ end
+
def test_does_not_modify_options_argument
- options = {:presence => true}
+ options = { :presence => true }
Topic.validates :title, options
- assert_equal({:presence => true}, options)
+ assert_equal({ :presence => true }, options)
end
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 5df3ec406f..ad9a12fc9b 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Add html_escape_once to ERB::Util, and delegate escape_once tag helper to it. *Carlos Antonio da Silva*
+
* Remove ActiveSupport::TestCase#pending method, use `skip` instead. *Carlos Antonio da Silva*
* Deprecates the compatibility method Module#local_constant_names,
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 73aa7dd89a..104ee251de 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -5,6 +5,8 @@ class ERB
module Util
HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
+ HTML_ESCAPE_ONCE_REGEXP = /[\"><]|&(?!([a-zA-Z]+|(#\d+));)/
+ JSON_ESCAPE_REGEXP = /[&"><]/
# A utility method for escaping HTML tag characters.
# This method is also aliased as <tt>h</tt>.
@@ -33,6 +35,21 @@ class ERB
singleton_class.send(:remove_method, :html_escape)
module_function :html_escape
+ # Returns an escaped version of +html+ without affecting existing escaped entities.
+ #
+ # ==== Examples
+ # html_escape_once("1 < 2 &amp; 3")
+ # # => "1 &lt; 2 &amp; 3"
+ #
+ # html_escape_once("&lt;&lt; Accept & Checkout")
+ # # => "&lt;&lt; Accept &amp; Checkout"
+ def html_escape_once(s)
+ result = s.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP) { |special| HTML_ESCAPE[special] }
+ s.html_safe? ? result.html_safe : result
+ end
+
+ module_function :html_escape_once
+
# A utility method for escaping HTML entities in JSON strings
# using \uXXXX JavaScript escape sequences for string literals:
#
@@ -51,7 +68,7 @@ class ERB
# <%=j @person.to_json %>
#
def json_escape(s)
- result = s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
+ result = s.to_s.gsub(JSON_ESCAPE_REGEXP) { |special| JSON_ESCAPE[special] }
s.html_safe? ? result.html_safe : result
end
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index ac61870871..9a748dfa60 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -1,4 +1,5 @@
# encoding: utf-8
+require 'active_support/json'
require 'active_support/core_ext/string/access'
require 'active_support/core_ext/string/behavior'
require 'active_support/core_ext/module/delegation'
@@ -188,6 +189,10 @@ module ActiveSupport #:nodoc:
chars(Unicode.tidy_bytes(@wrapped_string, force))
end
+ def as_json(options = nil) #:nodoc:
+ to_s.as_json(options)
+ end
+
%w(capitalize downcase reverse tidy_bytes upcase).each do |method|
define_method("#{method}!") do |*args|
@wrapped_string = send(method, *args).to_s
diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb
index 63e7a35c01..90aa13b3e6 100644
--- a/activesupport/test/multibyte_chars_test.rb
+++ b/activesupport/test/multibyte_chars_test.rb
@@ -88,6 +88,9 @@ class MultibyteCharsTest < ActiveSupport::TestCase
assert(('a'.mb_chars << 'b'.mb_chars).kind_of?(@proxy_class))
end
+ def test_should_return_string_as_json
+ assert_equal UNICODE_STRING, @chars.as_json
+ end
end
class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase