diff options
Diffstat (limited to 'actionview')
24 files changed, 185 insertions, 71 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index 9ea250643a..82a88952c3 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,8 @@ +* Add a `hidden_field` on the `collection_radio_buttons` to avoid raising a error + when the only input on the form is the `collection_radio_buttons`. + + *Mauro George* + * `url_for` does not modify its arguments when generating polymorphic URLs. *Bernerd Schaefer* diff --git a/actionview/lib/action_view/dependency_tracker.rb b/actionview/lib/action_view/dependency_tracker.rb index 6e8c7f8203..7716955fd9 100644 --- a/actionview/lib/action_view/dependency_tracker.rb +++ b/actionview/lib/action_view/dependency_tracker.rb @@ -1,9 +1,9 @@ -require 'thread_safe' +require 'concurrent' require 'action_view/path_set' module ActionView class DependencyTracker # :nodoc: - @trackers = ThreadSafe::Cache.new + @trackers = Concurrent::Map.new def self.find_dependencies(name, template, view_paths = nil) tracker = @trackers[template.handler] diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index 9a8a4feb2e..12e9723a02 100644 --- a/actionview/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb @@ -1,11 +1,11 @@ -require 'thread_safe' +require 'concurrent' require 'action_view/dependency_tracker' require 'monitor' module ActionView class Digestor cattr_reader(:cache) - @@cache = ThreadSafe::Cache.new + @@cache = Concurrent::Map.new @@digest_monitor = Monitor.new class PerRequestDigestCacheExpiry < Struct.new(:app) # :nodoc: @@ -28,7 +28,7 @@ module ActionView cache_key = ([ options[:name], options[:finder].details_key.hash ].compact + Array.wrap(options[:dependencies])).join('.') # this is a correctly done double-checked locking idiom - # (ThreadSafe::Cache's lookups have volatile semantics) + # (Concurrent::Map's lookups have volatile semantics) @@cache[cache_key] || @@digest_monitor.synchronize do @@cache.fetch(cache_key) do # re-check under lock compute_and_store_digest(cache_key, options) diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index ebf5ea5b77..2a367b85af 100644 --- a/actionview/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -849,8 +849,8 @@ module ActionView # file_field(:user, :avatar) # # => <input type="file" id="user_avatar" name="user[avatar]" /> # - # file_field(:post, :image, :multiple => true) - # # => <input type="file" id="post_image" name="post[image]" multiple="true" /> + # file_field(:post, :image, multiple: true) + # # => <input type="file" id="post_image" name="post[image][]" multiple="multiple" /> # # file_field(:post, :attached, accept: 'text/html') # # => <input accept="text/html" type="file" id="post_attached" name="post[attached]" /> @@ -1038,7 +1038,7 @@ module ActionView # date_field("user", "born_on") # # => <input id="user_born_on" name="user[born_on]" type="date" /> # - # The default value is generated by trying to call "to_date" + # The default value is generated by trying to call +strftime+ with "%Y-%m-%d" # on the object's value, which makes it behave as expected for instances # of DateTime and ActiveSupport::TimeWithZone. You can still override that # by passing the "value" option explicitly, e.g. @@ -1617,7 +1617,14 @@ module ActionView @auto_index end - record_name = index ? "#{object_name}[#{index}][#{record_name}]" : "#{object_name}[#{record_name}]" + record_name = if index + "#{object_name}[#{index}][#{record_name}]" + elsif record_name.to_s.end_with?('[]') + record_name = record_name.to_s.sub(/(.*)\[\]$/, "[\\1][#{record_object.id}]") + "#{object_name}#{record_name}" + else + "#{object_name}[#{record_name}]" + end fields_options[:child_index] = index @template.fields_for(record_name, record_object, fields_options, &block) diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index 728e633bbf..430051379d 100644 --- a/actionview/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -548,7 +548,7 @@ module ActionView end # Returns a string of option tags for pretty much any time zone in the - # world. Supply a ActiveSupport::TimeZone name as +selected+ to have it + # world. Supply an ActiveSupport::TimeZone name as +selected+ to have it # marked as the selected option tag. You can also supply an array of # ActiveSupport::TimeZone objects as +priority_zones+, so that they will # be listed above the rest of the (long) list. (You can use @@ -556,7 +556,7 @@ module ActionView # of the US time zones, or a Regexp to select the zones of your choice) # # The +selected+ parameter must be either +nil+, or a string that names - # a ActiveSupport::TimeZone. + # an ActiveSupport::TimeZone. # # By default, +model+ is the ActiveSupport::TimeZone constant (which can # be obtained in Active Record as a value object). The only requirement @@ -644,6 +644,24 @@ module ActionView # collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b| # b.label(:"data-value" => b.value) { b.radio_button + b.text } # end + # + # ==== Gotcha + # + # The HTML specification says when nothing is select on a collection of radio buttons + # web browsers do not send any value to server. + # Unfortunately this introduces a gotcha: + # if a +User+ model has a +category_id+ field, and in the form none category is selected no +category_id+ parameter is sent. So, + # any strong parameters idiom like + # + # params.require(:user).permit(...) + # + # will raise an error since no +{user: ...}+ will be present. + # + # To prevent this the helper generates an auxiliary hidden field before + # every collection of radio buttons. The hidden field has the same name as collection radio button and blank value. + # + # In case if you don't want the helper to generate this hidden field you can specify + # <tt>include_hidden: false</tt> option. def collection_radio_buttons(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block) Tags::CollectionRadioButtons.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block) end diff --git a/actionview/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb index 13effa592d..d7182d1fac 100644 --- a/actionview/lib/action_view/helpers/number_helper.rb +++ b/actionview/lib/action_view/helpers/number_helper.rb @@ -1,4 +1,3 @@ - require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/string/output_safety' require 'active_support/number_helper' @@ -140,7 +139,7 @@ module ActionView # number_to_percentage(302.24398923423, precision: 5) # => 302.24399% # number_to_percentage(1000, locale: :fr) # => 1 000,000% # number_to_percentage("98a") # => 98a% - # number_to_percentage(100, format: "%n %") # => 100 % + # number_to_percentage(100, format: "%n %") # => 100.000 % # # number_to_percentage("98a", raise: true) # => InvalidNumberError def number_to_percentage(number, options = {}) diff --git a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb index 1765fa6558..3256d44e18 100644 --- a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb +++ b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb @@ -9,29 +9,13 @@ module ActionView class CheckBoxBuilder < Builder # :nodoc: def check_box(extra_html_options={}) html_options = extra_html_options.merge(@input_html_options) + html_options[:multiple] = true @template_object.check_box(@object_name, @method_name, html_options, @value, nil) end end def render(&block) - rendered_collection = render_collection do |item, value, text, default_html_options| - default_html_options[:multiple] = true - builder = instantiate_builder(CheckBoxBuilder, item, value, text, default_html_options) - - if block_given? - @template_object.capture(builder, &block) - else - render_component(builder) - end - end - - # Append a hidden field to make sure something will be sent back to the - # server if all check boxes are unchecked. - if @options.fetch(:include_hidden, true) - rendered_collection + hidden_field - else - rendered_collection - end + render_collection_for(CheckBoxBuilder, &block) end private @@ -39,11 +23,6 @@ module ActionView def render_component(builder) builder.check_box + builder.label end - - def hidden_field - hidden_name = @html_options[:name] || "#{tag_name(false, @options[:index])}[]" - @template_object.hidden_field_tag(hidden_name, "", id: nil) - end end end end diff --git a/actionview/lib/action_view/helpers/tags/collection_helpers.rb b/actionview/lib/action_view/helpers/tags/collection_helpers.rb index 8050638363..fea4c8d4ec 100644 --- a/actionview/lib/action_view/helpers/tags/collection_helpers.rb +++ b/actionview/lib/action_view/helpers/tags/collection_helpers.rb @@ -79,6 +79,32 @@ module ActionView yield item, value, text, default_html_options.merge(additional_html_options) end.join.html_safe end + + def render_collection_for(builder_class, &block) #:nodoc: + options = @options.stringify_keys + rendered_collection = render_collection do |item, value, text, default_html_options| + builder = instantiate_builder(builder_class, item, value, text, default_html_options) + + if block_given? + @template_object.capture(builder, &block) + else + render_component(builder) + end + end + + # Append a hidden field to make sure something will be sent back to the + # server if all radio buttons are unchecked. + if options.fetch('include_hidden', true) + rendered_collection + hidden_field + else + rendered_collection + end + end + + def hidden_field #:nodoc: + hidden_name = @html_options[:name] || "#{tag_name(false, @options[:index])}[]" + @template_object.hidden_field_tag(hidden_name, "", id: nil) + end end end end diff --git a/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb index 20be34c1f2..21aaf122f8 100644 --- a/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb +++ b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb @@ -14,15 +14,7 @@ module ActionView end def render(&block) - render_collection do |item, value, text, default_html_options| - builder = instantiate_builder(RadioButtonBuilder, item, value, text, default_html_options) - - if block_given? - @template_object.capture(builder, &block) - else - render_component(builder) - end - end + render_collection_for(RadioButtonBuilder, &block) end private diff --git a/actionview/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb index 0615bd2e0d..dde1ef22ac 100644 --- a/actionview/lib/action_view/helpers/translation_helper.rb +++ b/actionview/lib/action_view/helpers/translation_helper.rb @@ -88,7 +88,14 @@ module ActionView raise e if raise_error keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope]) - content_tag('span', keys.last.to_s.titleize, :class => 'translation_missing', :title => "translation missing: #{keys.join('.')}") + title = "translation missing: #{keys.join('.')}" + + interpolations = options.except(:default) + if interpolations.any? + title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(', ') + end + + content_tag('span', keys.last.to_s.titleize, class: 'translation_missing', title: title) end end alias :t :translate diff --git a/actionview/lib/action_view/lookup_context.rb b/actionview/lib/action_view/lookup_context.rb index fba9a44cb1..ec6edfaaa3 100644 --- a/actionview/lib/action_view/lookup_context.rb +++ b/actionview/lib/action_view/lookup_context.rb @@ -1,4 +1,4 @@ -require 'thread_safe' +require 'concurrent' require 'active_support/core_ext/module/remove_method' require 'active_support/core_ext/module/attribute_accessors' require 'action_view/template/resolver' @@ -20,7 +20,7 @@ module ActionView mattr_accessor :registered_details self.registered_details = [] - def self.register_detail(name, options = {}, &block) + def self.register_detail(name, &block) self.registered_details << name initialize = registered_details.map { |n| "@details[:#{n}] = details[:#{n}] || default_#{n}" } @@ -55,14 +55,14 @@ module ActionView end register_detail(:formats) { ActionView::Base.default_formats || [:html, :text, :js, :css, :xml, :json] } register_detail(:variants) { [] } - register_detail(:handlers){ Template::Handlers.extensions } + register_detail(:handlers) { Template::Handlers.extensions } class DetailsKey #:nodoc: alias :eql? :equal? alias :object_hash :hash attr_reader :hash - @details_keys = ThreadSafe::Cache.new + @details_keys = Concurrent::Map.new def self.get(details) if details[:formats] diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb index 1f9e960488..39c8658ffe 100644 --- a/actionview/lib/action_view/renderer/partial_renderer.rb +++ b/actionview/lib/action_view/renderer/partial_renderer.rb @@ -1,5 +1,5 @@ require 'action_view/renderer/partial_renderer/collection_caching' -require 'thread_safe' +require 'concurrent' module ActionView class PartialIteration @@ -283,8 +283,8 @@ module ActionView class PartialRenderer < AbstractRenderer include CollectionCaching - PREFIXED_PARTIAL_NAMES = ThreadSafe::Cache.new do |h, k| - h[k] = ThreadSafe::Cache.new + PREFIXED_PARTIAL_NAMES = Concurrent::Map.new do |h, k| + h[k] = Concurrent::Map.new end def initialize(*) diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb index 28967f40a6..7859c58b43 100644 --- a/actionview/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb @@ -3,7 +3,7 @@ require "active_support/core_ext/class" require "active_support/core_ext/module/attribute_accessors" require "action_view/template" require "thread" -require "thread_safe" +require "concurrent" module ActionView # = Action View Resolver @@ -35,7 +35,7 @@ module ActionView # Threadsafe template cache class Cache #:nodoc: - class SmallCache < ThreadSafe::Cache + class SmallCache < Concurrent::Map def initialize(options = {}) super(options.merge(:initial_capacity => 2)) end diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb index 12870acaa6..2354e91822 100644 --- a/actionview/test/abstract_unit.rb +++ b/actionview/test/abstract_unit.rb @@ -151,7 +151,6 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase middleware.use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public") middleware.use ActionDispatch::DebugExceptions middleware.use ActionDispatch::Callbacks - middleware.use ActionDispatch::ParamsParser middleware.use ActionDispatch::Cookies middleware.use ActionDispatch::Flash middleware.use Rack::Head diff --git a/actionview/test/actionpack/controller/capture_test.rb b/actionview/test/actionpack/controller/capture_test.rb index f8387b27b0..933456ce9d 100644 --- a/actionview/test/actionpack/controller/capture_test.rb +++ b/actionview/test/actionpack/controller/capture_test.rb @@ -54,7 +54,7 @@ class CaptureTest < ActionController::TestCase assert_equal expected_content_for_output, @response.body end - def test_should_concatentate_content_for + def test_should_concatenate_content_for get :content_for_concatenated assert_equal expected_content_for_output, @response.body end diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb index 8d048ddbcb..27150c7d5f 100644 --- a/actionview/test/actionpack/controller/render_test.rb +++ b/actionview/test/actionpack/controller/render_test.rb @@ -1122,7 +1122,7 @@ class RenderTest < ActionController::TestCase assert_equal "<title>Putting stuff in the title!</title>\nGreat stuff!\n", @response.body end - def test_overwritting_rendering_relative_file_with_extension + def test_overwriting_rendering_relative_file_with_extension get :hello_world_from_rxml_using_template assert_equal "<html>\n <p>Hello</p>\n</html>\n", @response.body diff --git a/actionview/test/template/dependency_tracker_test.rb b/actionview/test/template/dependency_tracker_test.rb index 672b4747ec..3ece9e50cd 100644 --- a/actionview/test/template/dependency_tracker_test.rb +++ b/actionview/test/template/dependency_tracker_test.rb @@ -1,4 +1,3 @@ - require 'abstract_unit' require 'action_view/dependency_tracker' diff --git a/actionview/test/template/form_collections_helper_test.rb b/actionview/test/template/form_collections_helper_test.rb index b193d387c3..41932d15ee 100644 --- a/actionview/test/template/form_collections_helper_test.rb +++ b/actionview/test/template/form_collections_helper_test.rb @@ -198,6 +198,41 @@ class FormCollectionsHelperTest < ActionView::TestCase assert_select 'input[type=radio][value=false][checked=checked]' end + test 'collection radio buttons generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_radio_buttons :user, :category_ids, collection, :id, :name + + assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 1 + end + + test 'collection radio buttons generates a hidden field using the given :name in :html_options' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_radio_buttons :user, :category_ids, collection, :id, :name, {}, { name: "user[other_category_ids][]" } + + assert_select "input[type=hidden][name='user[other_category_ids][]'][value='']", count: 1 + end + + test 'collection radio buttons generates a hidden field with index if it was provided' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_radio_buttons :user, :category_ids, collection, :id, :name, { index: 322 } + + assert_select "input[type=hidden][name='user[322][category_ids][]'][value='']", count: 1 + end + + test 'collection radio buttons does not generate a hidden field if include_hidden option is false' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_radio_buttons :user, :category_ids, collection, :id, :name, include_hidden: false + + assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 0 + end + + test 'collection radio buttons does not generate a hidden field if include_hidden option is false with key as string' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_radio_buttons :user, :category_ids, collection, :id, :name, 'include_hidden' => false + + assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 0 + end + # COLLECTION CHECK BOXES test 'collection check boxes accepts a collection and generate a series of checkboxes for value method' do collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] @@ -235,6 +270,13 @@ class FormCollectionsHelperTest < ActionView::TestCase assert_select "input[type=hidden][name='user[category_ids][]'][value='']", :count => 0 end + test 'collection check boxes does not generate a hidden field if include_hidden option is false with key as string' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_check_boxes :user, :category_ids, collection, :id, :name, 'include_hidden' => false + + assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 0 + end + test 'collection check boxes accepts a collection and generate a series of checkboxes with labels for label method' do collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] with_collection_check_boxes :user, :category_ids, collection, :id, :name diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb index aef137935a..41f31f1582 100644 --- a/actionview/test/template/form_helper_test.rb +++ b/actionview/test/template/form_helper_test.rb @@ -366,7 +366,7 @@ class FormHelperTest < ActionView::TestCase ) end - def test_label_with_to_model_and_overriden_model_name + def test_label_with_to_model_and_overridden_model_name with_locale :label do assert_dom_equal( %{<label for="post_delegator_title">Delegate model_name title</label>}, @@ -1596,7 +1596,8 @@ class FormHelperTest < ActionView::TestCase "<input id='post_active_true' name='post[active]' type='radio' value='true' />" + "<label for='post_active_true'>true</label>" + "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" + - "<label for='post_active_false'>false</label>" + "<label for='post_active_false'>false</label>" + + "<input type='hidden' name='post[active][]' value='' />" end assert_dom_equal expected, output_buffer @@ -1619,7 +1620,8 @@ class FormHelperTest < ActionView::TestCase "true</label>" + "<label for='post_active_false'>"+ "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" + - "false</label>" + "false</label>" + + "<input type='hidden' name='post[active][]' value='' />" end assert_dom_equal expected, output_buffer @@ -1645,6 +1647,7 @@ class FormHelperTest < ActionView::TestCase "<label for='post_active_false'>"+ "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" + "false</label>"+ + "<input type='hidden' name='post[active][]' value='' />" + "<input id='post_id' name='post[id]' type='hidden' value='1' />" end @@ -1663,7 +1666,8 @@ class FormHelperTest < ActionView::TestCase "<input id='foo_post_active_true' name='post[active]' type='radio' value='true' />" + "<label for='foo_post_active_true'>true</label>" + "<input checked='checked' id='foo_post_active_false' name='post[active]' type='radio' value='false' />" + - "<label for='foo_post_active_false'>false</label>" + "<label for='foo_post_active_false'>false</label>" + + "<input type='hidden' name='post[active][]' value='' />" end assert_dom_equal expected, output_buffer @@ -1681,7 +1685,8 @@ class FormHelperTest < ActionView::TestCase "<input id='post_1_active_true' name='post[1][active]' type='radio' value='true' />" + "<label for='post_1_active_true'>true</label>" + "<input checked='checked' id='post_1_active_false' name='post[1][active]' type='radio' value='false' />" + - "<label for='post_1_active_false'>false</label>" + "<label for='post_1_active_false'>false</label>" + + "<input type='hidden' name='post[1][active][]' value='' />" end assert_dom_equal expected, output_buffer @@ -2292,6 +2297,27 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_deep_nested_fields_for + @comment.save + form_for(:posts) do |f| + f.fields_for('post[]', @post) do |f2| + f2.text_field(:id) + @post.comments.each do |comment| + concat f2.fields_for('comment[]', comment) { |c| + concat c.text_field(:name) + } + end + end + end + + expected = whole_form do + "<input name='posts[post][0][comment][1][name]' type='text' id='posts_post_0_comment_1_name' value='comment #1' />" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_nested_collections form_for(@post, as: 'post[]') do |f| concat f.text_field(:title) diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb index 7e1324c011..8db35d02e1 100644 --- a/actionview/test/template/form_tag_helper_test.rb +++ b/actionview/test/template/form_tag_helper_test.rb @@ -450,21 +450,21 @@ class FormTagHelperTest < ActionView::TestCase ActionView::Base.automatically_disable_submit_tag = true end - def test_data_disable_with_string + def test_submit_tag_having_data_disable_with_string assert_dom_equal( %(<input data-disable-with="Processing..." data-confirm="Are you sure?" name='commit' type="submit" value="Save" />), submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" }) ) end - def test_data_disable_with_boolean + def test_submit_tag_having_data_disable_with_boolean assert_dom_equal( %(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />), submit_tag("Save", { "data-disable-with" => false, "data-confirm" => "Are you sure?" }) ) end - def test_data_hash_disable_with_boolean + def test_submit_tag_having_data_hash_disable_with_boolean assert_dom_equal( %(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />), submit_tag("Save", { :data => { :confirm => "Are you sure?", :disable_with => false } }) diff --git a/actionview/test/template/lookup_context_test.rb b/actionview/test/template/lookup_context_test.rb index 14dafd7d63..1184cf7da8 100644 --- a/actionview/test/template/lookup_context_test.rb +++ b/actionview/test/template/lookup_context_test.rb @@ -27,7 +27,7 @@ class LookupContextTest < ActiveSupport::TestCase end test "normalizes details on initialization" do - assert_equal Mime::SET, @lookup_context.formats + assert_equal Mime::SET.to_a, @lookup_context.formats assert_equal :en, @lookup_context.locale end @@ -48,11 +48,11 @@ class LookupContextTest < ActiveSupport::TestCase test "handles */* formats" do @lookup_context.formats = ["*/*"] - assert_equal Mime::SET, @lookup_context.formats + assert_equal Mime::SET.to_a, @lookup_context.formats end test "handles explicitly defined */* formats fallback to :js" do - @lookup_context.formats = [:js, Mime::ALL] + @lookup_context.formats = [:js, Mime::Type[:ALL]] assert_equal [:js, *Mime::SET.symbols], @lookup_context.formats end diff --git a/actionview/test/template/number_helper_test.rb b/actionview/test/template/number_helper_test.rb index 631d45586b..ace3e950b8 100644 --- a/actionview/test/template/number_helper_test.rb +++ b/actionview/test/template/number_helper_test.rb @@ -1,4 +1,3 @@ -# encoding: utf-8 require "abstract_unit" class NumberHelperTest < ActionView::TestCase diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb index 9c2c9507b7..00fc28a522 100644 --- a/actionview/test/template/render_test.rb +++ b/actionview/test/template/render_test.rb @@ -627,6 +627,16 @@ class CachedCollectionViewRenderTest < CachedViewRenderTest @view.render(partial: "test/customer", collection: [customer], cache: ->(item) { [item, 'key'] }) end + test "with caching with custom key and rendering with different key" do + customer = Customer.new("david") + key = cache_key([customer, 'key'], "test/_customer") + + ActionView::PartialRenderer.collection_cache.write(key, 'Hello') + + assert_equal "Hello: david", + @view.render(partial: "test/customer", collection: [customer], cache: ->(item) { [item, 'another_key'] }) + end + test "automatic caching with inferred cache name" do customer = CachedCustomer.new("david") key = cache_key(customer, "test/_cached_customer") diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb index 749d0dd7fd..261576bead 100644 --- a/actionview/test/template/translation_helper_test.rb +++ b/actionview/test/template/translation_helper_test.rb @@ -60,6 +60,12 @@ class TranslationHelperTest < ActiveSupport::TestCase assert_equal true, translate(:"translations.missing").html_safe? end + def test_returns_missing_translation_message_with_unescaped_interpolation + expected = '<span class="translation_missing" title="translation missing: en.translations.missing, name: Kir, year: 2015, vulnerable: &quot; onclick=&quot;alert()&quot;">Missing</span>' + assert_equal expected, translate(:"translations.missing", name: "Kir", year: "2015", vulnerable: %{" onclick="alert()"}) + assert translate(:"translations.missing").html_safe? + end + def test_raises_missing_translation_message_with_raise_config_option ActionView::Base.raise_on_missing_translations = true |