diff options
Diffstat (limited to 'actionview')
22 files changed, 180 insertions, 40 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index 957fb2fbcc..b961dce4d1 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,4 +1,77 @@ -* Remove deprecated block passing to FormBuilder#new. +* Fix `text_area` to behave like `text_field` when `nil` is given as + value. + + Before: + + f.text_field :field, value: nil #=> <input value=""> + f.text_area :field, value: nil #=> <textarea>value of field</textarea> + + After: + + f.text_area :field, value: nil #=> <textarea></textarea> + + *Joel Cogen* + +* Element of the `grouped_options_for_select` can + optionally contain html attributes as the last element of the array. + + grouped_options_for_select( + [["North America", [['United States','US'],"Canada"], data: { foo: 'bar' }]] + ) + + *Vasiliy Ermolovich* + +* Fix default rendered format problem when calling `render` without :content_type option. + It should return :html. Fix #11393. + + *Gleb Mazovetskiy* *Oleg* *kennyj* + +* Fix `link_to` with block and url hashes. + + Before: + + link_to(action: 'bar', controller: 'foo') { content_tag(:span, 'Example site') } + # => "<a action=\"bar\" controller=\"foo\"><span>Example site</span></a>" + + After: + + link_to(action: 'bar', controller: 'foo') { content_tag(:span, 'Example site') } + # => "<a href=\"/foo/bar\"><span>Example site</span></a>" + + *Murahashi Sanemat Kenichi* + +* Fix "Stack Level Too Deep" error when redering recursive partials. + + Fixes #11340. + + *Rafael Mendonça França* + +* Added an `enforce_utf8` hash option for `form_tag` method. + + Control to output a hidden input tag with name `utf8` without monkey + patching. + + Before: + + form_tag + # => '<form>..<input name="utf8" type="hidden" value="✓" />..</form>' + + After: + + form_tag + # => '<form>..<input name="utf8" type="hidden" value="✓" />..</form>' + + form_tag({}, { :enforce_utf8 => false }) + # => '<form>....</form>' + + *ma2gedev* + +* Remove the deprecated `include_seconds` argument from `distance_of_time_in_words`, + pass in an `:include_seconds` hash option to use this feature. + + *Carlos Antonio da Silva* + +* Remove deprecated block passing to `FormBuilder#new`. *Vipul A M* diff --git a/actionview/README.rdoc b/actionview/README.rdoc index 09bbfdae0b..ab6c7e878a 100644 --- a/actionview/README.rdoc +++ b/actionview/README.rdoc @@ -1,7 +1,5 @@ = Action View - - == Download and installation The latest version of Action View can be installed with RubyGems: diff --git a/actionview/RUNNING_UNIT_TESTS b/actionview/RUNNING_UNIT_TESTS.rdoc index a0c35e1810..a0c35e1810 100644 --- a/actionview/RUNNING_UNIT_TESTS +++ b/actionview/RUNNING_UNIT_TESTS.rdoc diff --git a/actionview/Rakefile b/actionview/Rakefile index 1cbd35cda4..25365d3c3d 100644 --- a/actionview/Rakefile +++ b/actionview/Rakefile @@ -1,5 +1,4 @@ require 'rake/testtask' -require 'rake/packagetask' require 'rubygems/package_task' desc "Default Task" diff --git a/actionview/actionview.gemspec b/actionview/actionview.gemspec index 87cb568300..cdac074973 100644 --- a/actionview/actionview.gemspec +++ b/actionview/actionview.gemspec @@ -5,7 +5,7 @@ Gem::Specification.new do |s| s.name = 'actionview' s.version = version s.summary = 'Rendering framework putting the V in MVC (part of Rails).' - s.description = '' + s.description = 'Simple, battle-tested conventions and helpers for building web pages.' s.required_ruby_version = '>= 1.9.3' diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index 9324a1ac50..a674e4d7ea 100644 --- a/actionview/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb @@ -7,10 +7,14 @@ module ActionView @@cache = ThreadSafe::Cache.new def self.digest(name, format, finder, options = {}) - cache_key = [name, format] + Array.wrap(options[:dependencies]) - @@cache[cache_key.join('.')] ||= begin + cache_key = ([name, format] + Array.wrap(options[:dependencies])).join('.') + @@cache.fetch(cache_key) do + @@cache[cache_key] ||= nil if options[:partial] # Prevent re-entry + klass = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor - klass.new(name, format, finder, options).digest + digest = klass.new(name, format, finder, options).digest + + @@cache[cache_key] = digest # Store the value end end diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb index 8fb5eb1548..8e1aea50a9 100644 --- a/actionview/lib/action_view/helpers/date_helper.rb +++ b/actionview/lib/action_view/helpers/date_helper.rb @@ -64,15 +64,7 @@ module ActionView # distance_of_time_in_words(from_time, to_time, include_seconds: true) # => about 6 years # distance_of_time_in_words(to_time, from_time, include_seconds: true) # => about 6 years # distance_of_time_in_words(Time.now, Time.now) # => less than a minute - def distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {}) - if include_seconds_or_options.is_a?(Hash) - options = include_seconds_or_options - else - ActiveSupport::Deprecation.warn "distance_of_time_in_words and time_ago_in_words now accept :include_seconds " + - "as a part of options hash, not a boolean argument" - options[:include_seconds] ||= !!include_seconds_or_options - end - + def distance_of_time_in_words(from_time, to_time = 0, options = {}) options = { scope: :'datetime.distance_in_words' }.merge!(options) diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index 4e9ef94ff3..e7f932ca06 100644 --- a/actionview/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -346,8 +346,8 @@ module ActionView html_attributes = option_html_attributes(element) text, value = option_text_and_value(element).map { |item| item.to_s } - html_attributes[:selected] = 'selected' if option_value_selected?(value, selected) - html_attributes[:disabled] = 'disabled' if disabled && option_value_selected?(value, disabled) + html_attributes[:selected] = option_value_selected?(value, selected) + html_attributes[:disabled] = disabled && option_value_selected?(value, disabled) html_attributes[:value] = value content_tag_string(:option, text, html_attributes) @@ -384,8 +384,8 @@ module ActionView end selected, disabled = extract_selected_and_disabled(selected) select_deselect = { - :selected => extract_values_from_collection(collection, value_method, selected), - :disabled => extract_values_from_collection(collection, value_method, disabled) + selected: extract_values_from_collection(collection, value_method, selected), + disabled: extract_values_from_collection(collection, value_method, disabled) } options_for_select(options, select_deselect) @@ -444,7 +444,7 @@ module ActionView option_tags = options_from_collection_for_select( group.send(group_method), option_key_method, option_value_method, selected_key) - content_tag(:optgroup, option_tags, :label => group.send(group_label_method)) + content_tag(:optgroup, option_tags, label: group.send(group_label_method)) end.join.html_safe end @@ -516,16 +516,20 @@ module ActionView body = "".html_safe if prompt - body.safe_concat content_tag(:option, prompt_text(prompt), :value => "") + body.safe_concat content_tag(:option, prompt_text(prompt), value: "") end grouped_options.each do |container| + html_attributes = option_html_attributes(container) + if divider label = divider else label, container = container end - body.safe_concat content_tag(:optgroup, options_for_select(container, selected_key), :label => label) + + html_attributes = { label: label }.merge!(html_attributes) + body.safe_concat content_tag(:optgroup, options_for_select(container, selected_key), html_attributes) end body @@ -561,7 +565,7 @@ module ActionView end zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected) - zone_options.safe_concat content_tag(:option, '-------------', :value => '', :disabled => 'disabled') + zone_options.safe_concat content_tag(:option, '-------------', value: '', disabled: true) zone_options.safe_concat "\n" zones = zones - priority_zones @@ -744,7 +748,7 @@ module ActionView end def prompt_text(prompt) - prompt.kind_of?(String) ? prompt : I18n.translate('helpers.select.prompt', :default => 'Please select') + prompt.kind_of?(String) ? prompt : I18n.translate('helpers.select.prompt', default: 'Please select') end end @@ -752,7 +756,7 @@ module ActionView # Wraps ActionView::Helpers::FormOptionsHelper#select for form builders: # # <%= form_for @post do |f| %> - # <%= f.select :person_id, Person.all.collect {|p| [ p.name, p.id ] }, { include_blank: true }) %> + # <%= f.select :person_id, Person.all.collect { |p| [ p.name, p.id ] }, include_blank: true %> # <%= f.submit %> # <% end %> # diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb index 3fa7696b83..142c27ace0 100644 --- a/actionview/lib/action_view/helpers/form_tag_helper.rb +++ b/actionview/lib/action_view/helpers/form_tag_helper.rb @@ -38,6 +38,7 @@ module ActionView # * A list of parameters to feed to the URL the form will be posted to. # * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the # submit behavior. By default this behavior is an ajax submit. + # * <tt>:enforce_utf8</tt> - If set to false, a hidden input with name utf8 is not output. # # ==== Examples # form_tag('/posts') @@ -719,7 +720,8 @@ module ActionView method_tag(method) + token_tag(authenticity_token) end - tags = utf8_enforcer_tag << method_tag + enforce_utf8 = html_options.delete("enforce_utf8") { true } + tags = (enforce_utf8 ? utf8_enforcer_tag : ''.html_safe) << method_tag content_tag(:div, tags, :style => 'margin:0;padding:0;display:inline') end diff --git a/actionview/lib/action_view/helpers/tags/text_area.rb b/actionview/lib/action_view/helpers/tags/text_area.rb index c81156c0c8..9ee83ee7c2 100644 --- a/actionview/lib/action_view/helpers/tags/text_area.rb +++ b/actionview/lib/action_view/helpers/tags/text_area.rb @@ -10,7 +10,7 @@ module ActionView options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split) end - content_tag("textarea", options.delete('value') || value_before_type_cast(object), options) + content_tag("textarea", options.delete("value") { value_before_type_cast(object) }, options) end end end diff --git a/actionview/lib/action_view/helpers/tags/text_field.rb b/actionview/lib/action_view/helpers/tags/text_field.rb index baa5ff768e..e910879ebf 100644 --- a/actionview/lib/action_view/helpers/tags/text_field.rb +++ b/actionview/lib/action_view/helpers/tags/text_field.rb @@ -5,8 +5,8 @@ module ActionView def render options = @options.stringify_keys options["size"] = options["maxlength"] unless options.key?("size") - options["type"] ||= field_type - options["value"] = options.fetch("value"){ value_before_type_cast(object) } unless field_type == "file" + options["type"] ||= field_type + options["value"] = options.fetch("value") { value_before_type_cast(object) } unless field_type == "file" options["value"] &&= ERB::Util.html_escape(options["value"]) add_default_name_and_id(options) tag("input", options) diff --git a/actionview/lib/action_view/helpers/text_helper.rb b/actionview/lib/action_view/helpers/text_helper.rb index 147f9fd8ed..6fe250d3c1 100644 --- a/actionview/lib/action_view/helpers/text_helper.rb +++ b/actionview/lib/action_view/helpers/text_helper.rb @@ -254,7 +254,7 @@ module ActionView # # => "<p>Unblinkable.</p>" # # simple_format("<blink>Blinkable!</blink> It's true.", {}, sanitize: false) - # # => "<p><blink>Blinkable!</span> It's true.</p>" + # # => "<p><blink>Blinkable!</blink> It's true.</p>" def simple_format(text, html_options = {}, options = {}) wrapper_tag = options.fetch(:wrapper_tag, :p) diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb index 19e5941971..a4f04b0b3b 100644 --- a/actionview/lib/action_view/helpers/url_helper.rb +++ b/actionview/lib/action_view/helpers/url_helper.rb @@ -16,7 +16,7 @@ module ActionView # provided here will only work in the context of a request # (link_to_unless_current, for instance), which must be provided # as a method called #request on the context. - + BUTTON_TAG_METHOD_VERBS = %w{patch put delete} extend ActiveSupport::Concern include TagHelper @@ -172,7 +172,7 @@ module ActionView # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" } # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a> def link_to(name = nil, options = nil, html_options = nil, &block) - html_options, options = options, name if block_given? + html_options, options, name = options, name, block if block_given? options ||= {} html_options = convert_options_to_data_attributes(options, html_options) @@ -289,7 +289,7 @@ module ActionView remote = html_options.delete('remote') method = html_options.delete('method').to_s - method_tag = %w{patch put delete}.include?(method) ? method_tag(method) : ''.html_safe + method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.html_safe form_method = method == 'get' ? 'get' : 'post' form_options = html_options.delete('form') || {} diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb index 4d5c5db80c..668831dff3 100644 --- a/actionview/lib/action_view/renderer/template_renderer.rb +++ b/actionview/lib/action_view/renderer/template_renderer.rb @@ -11,7 +11,7 @@ module ActionView prepend_formats(template.formats) unless context.rendered_format - context.rendered_format = template.formats.first || formats.last + context.rendered_format = template.formats.first || formats.first end render_template(template, options[:layout], options[:locals]) diff --git a/actionview/test/fixtures/digestor/level/_recursion.html.erb b/actionview/test/fixtures/digestor/level/_recursion.html.erb new file mode 100644 index 0000000000..ee5aaf09c3 --- /dev/null +++ b/actionview/test/fixtures/digestor/level/_recursion.html.erb @@ -0,0 +1 @@ +<%= render 'recursion' %> diff --git a/actionview/test/fixtures/digestor/level/recursion.html.erb b/actionview/test/fixtures/digestor/level/recursion.html.erb new file mode 100644 index 0000000000..ee5aaf09c3 --- /dev/null +++ b/actionview/test/fixtures/digestor/level/recursion.html.erb @@ -0,0 +1 @@ +<%= render 'recursion' %> diff --git a/actionview/test/template/digestor_test.rb b/actionview/test/template/digestor_test.rb index 06735c30d3..67e3775f28 100644 --- a/actionview/test/template/digestor_test.rb +++ b/actionview/test/template/digestor_test.rb @@ -95,6 +95,31 @@ class TemplateDigestorTest < ActionView::TestCase end end + def test_recursion_in_renders + assert digest("level/recursion") # assert recursion is possible + assert_not_nil digest("level/recursion") # assert digest is stored + end + + def test_chaining_the_top_template_on_recursion + assert digest("level/recursion") # assert recursion is possible + + assert_digest_difference("level/recursion") do + change_template("level/recursion") + end + + assert_not_nil digest("level/recursion") # assert digest is stored + end + + def test_chaining_the_partial_template_on_recursion + assert digest("level/recursion") # assert recursion is possible + + assert_digest_difference("level/recursion") do + change_template("level/_recursion") + end + + assert_not_nil digest("level/recursion") # assert digest is stored + end + def test_dont_generate_a_digest_for_missing_templates assert_equal '', digest("nothing/there") end diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb index f05b6d0d94..8cca43d7ca 100644 --- a/actionview/test/template/form_helper_test.rb +++ b/actionview/test/template/form_helper_test.rb @@ -676,6 +676,13 @@ class FormHelperTest < ActionView::TestCase ) end + def test_text_area_with_nil_alternate_value + assert_dom_equal( + %{<textarea id="post_body" name="post[body]">\n</textarea>}, + text_area("post", "body", value: nil) + ) + end + def test_text_area_with_html_entities @post.body = "The HTML Entity for & is &" assert_dom_equal( diff --git a/actionview/test/template/form_options_helper_test.rb b/actionview/test/template/form_options_helper_test.rb index 8c90a58a84..3ec138b639 100644 --- a/actionview/test/template/form_options_helper_test.rb +++ b/actionview/test/template/form_options_helper_test.rb @@ -302,6 +302,16 @@ class FormOptionsHelperTest < ActionView::TestCase ) end + def test_grouped_options_for_select_with_array_and_html_attributes + assert_dom_equal( + "<optgroup label=\"North America\" data-foo=\"bar\"><option value=\"US\">United States</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"Europe\" disabled=\"disabled\"><option value=\"GB\">Great Britain</option>\n<option value=\"Germany\">Germany</option></optgroup>", + grouped_options_for_select([ + ["North America", [['United States','US'],"Canada"], :data => { :foo => 'bar' }], + ["Europe", [["Great Britain","GB"], "Germany"], :disabled => 'disabled'] + ]) + ) + end + def test_grouped_options_for_select_with_optional_divider assert_dom_equal( "<optgroup label=\"----------\"><option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"----------\"><option value=\"GB\">GB</option>\n<option value=\"Germany\">Germany</option></optgroup>", diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb index 70fc6a588b..22bf438a56 100644 --- a/actionview/test/template/form_tag_helper_test.rb +++ b/actionview/test/template/form_tag_helper_test.rb @@ -12,9 +12,10 @@ class FormTagHelperTest < ActionView::TestCase def hidden_fields(options = {}) method = options[:method] + enforce_utf8 = options.fetch(:enforce_utf8, true) txt = %{<div style="margin:0;padding:0;display:inline">} - txt << %{<input name="utf8" type="hidden" value="✓" />} + txt << %{<input name="utf8" type="hidden" value="✓" />} if enforce_utf8 if method && !%w(get post).include?(method.to_s) txt << %{<input name="_method" type="hidden" value="#{method}" />} end @@ -110,6 +111,20 @@ class FormTagHelperTest < ActionView::TestCase assert_dom_equal expected, actual end + def test_form_tag_enforce_utf8_true + actual = form_tag({}, { :enforce_utf8 => true }) + expected = whole_form("http://www.example.com", :enforce_utf8 => true) + assert_dom_equal expected, actual + assert actual.html_safe? + end + + def test_form_tag_enforce_utf8_false + actual = form_tag({}, { :enforce_utf8 => false }) + expected = whole_form("http://www.example.com", :enforce_utf8 => false) + assert_dom_equal expected, actual + assert actual.html_safe? + end + def test_form_tag_with_block_in_erb output_buffer = render_erb("<%= form_tag('http://www.example.com') do %>Hello world!<% end %>") diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb index 8cffe73cce..928dfb092d 100644 --- a/actionview/test/template/render_test.rb +++ b/actionview/test/template/render_test.rb @@ -41,6 +41,11 @@ module RenderTestCases assert_match "<error>No Comment</error>", @view.render(:template => "comments/empty", :formats => [:xml]) end + def test_rendered_format_without_format + @view.render(:inline => "test") + assert_equal :html, @view.lookup_context.rendered_format + end + def test_render_partial_implicitly_use_format_of_the_rendered_template @view.lookup_context.formats = [:json] assert_equal "Hello world", @view.render(:template => "test/one", :formats => [:html]) diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb index 8373d7f992..851ea8796f 100644 --- a/actionview/test/template/url_helper_test.rb +++ b/actionview/test/template/url_helper_test.rb @@ -308,6 +308,13 @@ class UrlHelperTest < ActiveSupport::TestCase link_to('/', class: "special") { content_tag(:span, 'Example site') } end + def test_link_tag_using_block_and_hash + assert_dom_equal( + %{<a href="/"><span>Example site</span></a>}, + link_to(url_hash) { content_tag(:span, 'Example site') } + ) + end + def test_link_tag_using_block_in_erb out = render_erb %{<%= link_to('/') do %>Example site<% end %>} assert_equal '<a href="/">Example site</a>', out @@ -336,8 +343,6 @@ class UrlHelperTest < ActiveSupport::TestCase assert_dom_equal %{<a href="/">Listing</a>}, link_to_unless(false, "Listing", url_hash) - assert_equal "Showing", link_to_unless(true, "Showing", url_hash) - assert_equal "<strong>Showing</strong>", link_to_unless(true, "Showing", url_hash) { |name| "<strong>#{name}</strong>".html_safe @@ -357,7 +362,6 @@ class UrlHelperTest < ActiveSupport::TestCase def test_link_to_if assert_equal "Showing", link_to_if(false, "Showing", url_hash) assert_dom_equal %{<a href="/">Listing</a>}, link_to_if(true, "Listing", url_hash) - assert_equal "Showing", link_to_if(false, "Showing", url_hash) end def request_for_url(url, opts = {}) |