Exception: ActionView::MissingTemplate

Inherits:
ActionViewError show all
Includes:
DidYouMean::Correctable
Defined in:
actionview/lib/action_view/template/error.rb

Overview

:nodoc:

Defined Under Namespace

Classes: Results

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(paths, path, prefixes, partial, details) ⇒ MissingTemplate

Returns a new instance of MissingTemplate.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'actionview/lib/action_view/template/error.rb', line 33

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

Instance Attribute Details

#partialObject (readonly)

Returns the value of attribute partial



31
32
33
# File 'actionview/lib/action_view/template/error.rb', line 31

def partial
  @partial
end

#pathObject (readonly)

Returns the value of attribute path



31
32
33
# File 'actionview/lib/action_view/template/error.rb', line 31

def path
  @path
end

#pathsObject (readonly)

Returns the value of attribute paths



31
32
33
# File 'actionview/lib/action_view/template/error.rb', line 31

def paths
  @paths
end

#prefixesObject (readonly)

Returns the value of attribute prefixes



31
32
33
# File 'actionview/lib/action_view/template/error.rb', line 31

def prefixes
  @prefixes
end

Instance Method Details

#correctionsObject

Apps may have thousands of candidate templates so we attempt to generate the suggestions as efficiently as possible. First we split templates into prefixes and basenames, so that those can be matched separately.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'actionview/lib/action_view/template/error.rb', line 93

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