From f80038ae7d03cf86a59e38d7242f9d1ecb2587b0 Mon Sep 17 00:00:00 2001 From: Adam Hess Date: Thu, 15 Apr 2021 10:15:52 -0700 Subject: [PATCH] Improve did_you_mean partial name correction Before this change did_you_mean shows partial paths like `animals/_partial`, but adding that to your render call in a view like `<%= render 'animals/_partial' %>` will still be missing as rails will search for the template `animals/__partial`. We can provide the user a easier copy/paste correction if we don't tell them about the underscore. This also reduces the candidates to only return partials if you are looking for a partial and only look for non-templates when you are not looking for a template. --- actionview/lib/action_view/template/error.rb | 15 +++++++++++++-- actionview/test/template/render_test.rb | 18 ++++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/actionview/lib/action_view/template/error.rb b/actionview/lib/action_view/template/error.rb index 6e05a5d674..7a14737df4 100644 --- a/actionview/lib/action_view/template/error.rb +++ b/actionview/lib/action_view/template/error.rb @@ -27,7 +27,7 @@ module ActionView end class MissingTemplate < ActionViewError #:nodoc: - attr_reader :path, :paths, :prefixes + attr_reader :path, :paths, :prefixes, :partial def initialize(paths, path, prefixes, partial, details, *) if partial && path.present? @@ -37,6 +37,7 @@ module ActionView @path = path @paths = paths @prefixes = Array(prefixes) + @partial = partial template_type = if partial "partial" elsif /layouts/i.match?(path) @@ -93,7 +94,13 @@ module ActionView def corrections path = @error.path prefixes = @error.prefixes + candidates = @error.paths.flat_map(&:all_template_paths).uniq + if @error.partial + candidates = candidates.grep(%r{_[^/]+\z}) + else + candidates = candidates.grep_v(%r{_[^/]+\z}) + end # Group by possible prefixes files_by_dir = candidates.group_by do |x| @@ -135,7 +142,11 @@ module ActionView end end - results.to_a + if @error.partial + results.to_a.map { |res| res.sub(%r{_([^/]+)\z}, "\\1") } + else + results.to_a + end end end diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb index b9d1b2e271..9f5aed8d03 100644 --- a/actionview/test/template/render_test.rb +++ b/actionview/test/template/render_test.rb @@ -626,13 +626,27 @@ module RenderTestCases if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error) def test_render_partial_provides_spellcheck e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/partail") } - assert_match %r{Did you mean\? test/_partial\n *test/_partialhtml}, e.message + assert_match %r{Did you mean\? test/partial\n *test/partialhtml}, e.message end def test_spellcheck_doesnt_list_directories e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/directory") } assert_match %r{Did you mean\?}, e.message - assert_no_match %r{Did you mean\? test/_directory\n}, e.message # test/hello is a directory + assert_no_match %r{Did you mean\? test/directory\n}, e.message # test/hello is a directory + end + + def test_spellcheck_only_lists_templates + e = assert_raises(ActionView::MissingTemplate) { @view.render(template: "test/partial") } + + assert_match %r{Did you mean\?}, e.message + assert_no_match %r{Did you mean\? test/partial\n}, e.message + end + + def test_spellcheck_only_lists_partials + e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: "test/template") } + + assert_match %r{Did you mean\?}, e.message + assert_no_match %r{Did you mean\? test/template\n}, e.message end end