class ActionView::MissingTemplate
:nodoc:
def corrections
First we split templates into prefixes and basenames, so that those can
generate the suggestions as efficiently as possible.
Apps may have thousands of candidate templates so we attempt to
def corrections candidates = paths.flat_map(&:all_template_paths).uniq if partial candidates.select!(&:partial?) else candidates.reject!(&:partial?) end # Group by possible prefixes files_by_dir = candidates.group_by(&:prefix) files_by_dir.transform_values! do |files| files.map do |file| # Remove prefix File.basename(file.to_s) end end # No suggestions if there's an exact match, but wrong details if prefixes.any? { |prefix| files_by_dir[prefix]&.include?(path) } return [] end cached_distance = Hash.new do |h, args| h[args] = -DidYouMean::Jaro.distance(*args) end results = Results.new(6) files_by_dir.keys.index_with do |dirname| prefixes.map do |prefix| cached_distance[[prefix, dirname]] end.min end.sort_by(&:last).each do |dirname, dirweight| # If our directory's score makes it impossible to find a better match # we can prune this search branch. next unless results.should_record?(dirweight - 1.0) files = files_by_dir[dirname] files.each do |file| fileweight = cached_distance[[path, file]] score = dirweight + fileweight results.add(File.join(dirname, file), score) end end if partial results.to_a.map { |res| res.sub(%r{_([^/]+)\z}, "\\1") } else results.to_a end end
def initialize(paths, path, prefixes, partial, details, *)
def initialize(paths, path, prefixes, partial, details, *) if partial && path.present? path = path.sub(%r{([^/]+)$}, "_\\1") end @path = path @paths = paths @prefixes = Array(prefixes) @partial = partial template_type = if partial "partial" elsif /layouts/i.match?(path) "layout" else "template" end searched_paths = @prefixes.map { |prefix| [prefix, path].join("/") } out = "Missing #{template_type} #{searched_paths.join(", ")} with #{details.inspect}.\n\nSearched in:\n" out += paths.compact.map { |p| " * #{p.to_s.inspect}\n" }.join super out end