diff options
Diffstat (limited to 'actionview')
23 files changed, 237 insertions, 131 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index d07794ddf3..17a5782f9f 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,22 +1,32 @@ ## Rails 6.0.0.beta3 (March 11, 2019) ## -* No changes. +* Only accept formats from registered mime types + + A lack of filtering on mime types could allow an attacker to read + arbitrary files on the target server or to perform a denial of service + attack. + + Fixes CVE-2019-5418 + Fixes CVE-2019-5419 + + *John Hawthorn*, *Eileen M. Uchitelle*, *Aaron Patterson* ## Rails 6.0.0.beta2 (February 25, 2019) ## -* ActionView::Template.finalize_compiled_template_methods is deprecated with +* `ActionView::Template.finalize_compiled_template_methods` is deprecated with no replacement. *tenderlove* -* config.action_view.finalize_compiled_template_methods is deprecated with +* `config.action_view.finalize_compiled_template_methods` is deprecated with no replacement. *tenderlove* * Ensure unique DOM IDs for collection inputs with float values. - Fixes #34974 + + Fixes #34974. *Mark Edmondson* diff --git a/actionview/lib/action_view/file_template.rb b/actionview/lib/action_view/file_template.rb index dea02176eb..e0dc7da3b6 100644 --- a/actionview/lib/action_view/file_template.rb +++ b/actionview/lib/action_view/file_template.rb @@ -11,7 +11,7 @@ module ActionView end def source - File.binread @filename + ::File.binread @filename end def refresh(_) diff --git a/actionview/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb index 279ef3c680..19fa399e2c 100644 --- a/actionview/lib/action_view/renderer/streaming_template_renderer.rb +++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb @@ -34,7 +34,7 @@ module ActionView return unless logger message = +"\n#{exception.class} (#{exception.message}):\n" - message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) + message << exception.annotated_source_code.to_s if exception.respond_to?(:annotated_source_code) message << " " << exception.backtrace.join("\n ") logger.fatal("#{message}\n\n") end diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb index 83b990b081..698f535b49 100644 --- a/actionview/lib/action_view/renderer/template_renderer.rb +++ b/actionview/lib/action_view/renderer/template_renderer.rb @@ -26,7 +26,12 @@ module ActionView elsif options.key?(:html) Template::HTML.new(options[:html], formats.first) elsif options.key?(:file) - @lookup_context.with_fallbacks.find_file(options[:file], nil, false, keys, @details) + if File.exist?(options[:file]) + Template::File.new(options[:file]) + else + ActiveSupport::Deprecation.warn "render file: should be given the absolute path to a file" + @lookup_context.with_fallbacks.find_file(options[:file], nil, false, keys, @details) + end elsif options.key?(:inline) handler = Template.handler_for_extension(options[:type] || "erb") format = if handler.respond_to?(:default_format) @@ -49,14 +54,14 @@ module ActionView # Renders the given template. A string representing the layout can be # supplied as well. def render_template(view, template, layout_name, locals) - render_with_layout(view, layout_name, template, locals) do |layout| + render_with_layout(view, template, layout_name, locals) do |layout| instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do template.render(view, locals) { |*name| view._layout_for(*name) } end end end - def render_with_layout(view, path, template, locals) + def render_with_layout(view, template, path, locals) layout = path && find_layout(path, locals.keys, [formats.first]) content = yield(layout) @@ -84,6 +89,7 @@ module ActionView when String begin if layout.start_with?("/") + ActiveSupport::Deprecation.warn "Rendering layouts from an absolute path is deprecated." @lookup_context.with_fallbacks.find_template(layout, nil, false, [], details) else @lookup_context.find_template(layout, nil, false, [], details) diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb index 6e3af1536a..ebe52532d6 100644 --- a/actionview/lib/action_view/template.rb +++ b/actionview/lib/action_view/template.rb @@ -113,6 +113,7 @@ module ActionView eager_autoload do autoload :Error + autoload :File autoload :Handlers autoload :HTML autoload :Inline @@ -139,7 +140,7 @@ module ActionView @virtual_path = virtual_path @variable = if @virtual_path - base = @virtual_path[-1] == "/" ? "" : File.basename(@virtual_path) + base = @virtual_path[-1] == "/" ? "" : ::File.basename(@virtual_path) base =~ /\A_?(.*?)(?:\.\w+)*\z/ $1.to_sym end @@ -331,6 +332,7 @@ module ActionView # Make sure that the resulting String to be eval'd is in the # encoding of the code + original_source = source source = +<<-end_src def #{method_name}(local_assigns, output_buffer) @virtual_path = #{@virtual_path.inspect};#{locals_code};#{code} @@ -351,7 +353,14 @@ module ActionView raise WrongEncodingError.new(source, Encoding.default_internal) end - mod.module_eval(source, identifier, 0) + begin + mod.module_eval(source, identifier, 0) + rescue SyntaxError + # Account for when code in the template is not syntactically valid; e.g. if we're using + # ERB and the user writes <%= foo( %>, attempting to call a helper `foo` and interpolate + # the result into the template, but missing an end parenthesis. + raise SyntaxErrorInTemplate.new(self, original_source) + end end def handle_render_error(view, e) diff --git a/actionview/lib/action_view/template/error.rb b/actionview/lib/action_view/template/error.rb index 4e3c02e05e..aace0be04d 100644 --- a/actionview/lib/action_view/template/error.rb +++ b/actionview/lib/action_view/template/error.rb @@ -104,12 +104,12 @@ module ActionView def line_number @line_number ||= if file_name - regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/ + regexp = /#{Regexp.escape ::File.basename(file_name)}:(\d+)/ $1 if message =~ regexp || backtrace.find { |line| line =~ regexp } end end - def annoted_source_code + def annotated_source_code source_extract(4) end @@ -138,4 +138,24 @@ module ActionView end TemplateError = Template::Error + + class SyntaxErrorInTemplate < TemplateError #:nodoc + def initialize(template, offending_code_string) + @offending_code_string = offending_code_string + super(template) + end + + def message + <<~MESSAGE + Encountered a syntax error while rendering template: check #{@offending_code_string} + MESSAGE + end + + def annotated_source_code + @offending_code_string.split("\n").map.with_index(1) { |line, index| + indentation = " " * 4 + "#{index}:#{indentation}#{line}" + } + end + end end diff --git a/actionview/lib/action_view/template/file.rb b/actionview/lib/action_view/template/file.rb new file mode 100644 index 0000000000..487e5735cf --- /dev/null +++ b/actionview/lib/action_view/template/file.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module ActionView #:nodoc: + # = Action View File Template + class Template #:nodoc: + class File #:nodoc: + attr_accessor :type, :format + + def initialize(filename) + @filename = filename.to_s + extname = ::File.extname(filename).delete(".") + @type = Template::Types[extname] || Template::Types[:text] + @format = @type.symbol + end + + def identifier + @filename + end + + def render(*args) + ::File.read(@filename) + end + + def formats; Array(format); end + deprecate :formats + end + end +end diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb index 1c577348e5..3b4c8a94bc 100644 --- a/actionview/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb @@ -168,7 +168,12 @@ module ActionView DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}" def initialize(pattern = nil) - @pattern = pattern || DEFAULT_PATTERN + if pattern + ActiveSupport::Deprecation.warn "Specifying a custom path for #{self.class} is deprecated. Implement a custom Resolver subclass instead." + @pattern = pattern + else + @pattern = DEFAULT_PATTERN + end super() end @@ -273,44 +278,7 @@ module ActionView end end - # A resolver that loads files from the filesystem. It allows setting your own - # resolving pattern. Such pattern can be a glob string supported by some variables. - # - # ==== Examples - # - # Default pattern, loads views the same way as previous versions of rails, eg. when you're - # looking for <tt>users/new</tt> it will produce query glob: <tt>users/new{.{en},}{.{html,js},}{.{erb,haml},}</tt> - # - # FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}") - # - # This one allows you to keep files with different formats in separate subdirectories, - # eg. <tt>users/new.html</tt> will be loaded from <tt>users/html/new.erb</tt> or <tt>users/new.html.erb</tt>, - # <tt>users/new.js</tt> from <tt>users/js/new.erb</tt> or <tt>users/new.js.erb</tt>, etc. - # - # FileSystemResolver.new("/path/to/views", ":prefix/{:formats/,}:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}") - # - # If you don't specify a pattern then the default will be used. - # - # In order to use any of the customized resolvers above in a Rails application, you just need - # to configure ActionController::Base.view_paths in an initializer, for example: - # - # ActionController::Base.view_paths = FileSystemResolver.new( - # Rails.root.join("app/views"), - # ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}", - # ) - # - # ==== Pattern format and variables - # - # Pattern has to be a valid glob string, and it allows you to use the - # following variables: - # - # * <tt>:prefix</tt> - usually the controller path - # * <tt>:action</tt> - name of the action - # * <tt>:locale</tt> - possible locale versions - # * <tt>:formats</tt> - possible request formats (for example html, json, xml...) - # * <tt>:variants</tt> - possible request variants (for example phone, tablet...) - # * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...) - # + # A resolver that loads files from the filesystem. class FileSystemResolver < PathResolver def initialize(path, pattern = nil) raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver) @@ -331,6 +299,10 @@ module ActionView # An Optimized resolver for Rails' most common case. class OptimizedFileSystemResolver < FileSystemResolver #:nodoc: + def initialize(path) + super(path) + end + private def find_template_paths_from_details(path, details) diff --git a/actionview/test/actionpack/abstract/abstract_controller_test.rb b/actionview/test/actionpack/abstract/abstract_controller_test.rb index 4d4e2b8ef2..eecc19d413 100644 --- a/actionview/test/actionpack/abstract/abstract_controller_test.rb +++ b/actionview/test/actionpack/abstract/abstract_controller_test.rb @@ -229,11 +229,11 @@ module AbstractController end class ActionMissingRespondToActionController < AbstractController::Base - # No actions - private - def action_missing(action_name) - self.response_body = "success" - end + # No actions + private + def action_missing(action_name) + self.response_body = "success" + end end class RespondToActionController < AbstractController::Base diff --git a/actionview/test/actionpack/abstract/render_test.rb b/actionview/test/actionpack/abstract/render_test.rb index d863548a5c..e4e8ac93b2 100644 --- a/actionview/test/actionpack/abstract/render_test.rb +++ b/actionview/test/actionpack/abstract/render_test.rb @@ -26,7 +26,7 @@ module AbstractController end def file - render file: "some/file" + ActiveSupport::Deprecation.silence { render file: "some/file" } end def inline diff --git a/actionview/test/actionpack/controller/layout_test.rb b/actionview/test/actionpack/controller/layout_test.rb index 838b564c5d..f946e4360d 100644 --- a/actionview/test/actionpack/controller/layout_test.rb +++ b/actionview/test/actionpack/controller/layout_test.rb @@ -233,7 +233,9 @@ class LayoutSetInResponseTest < ActionController::TestCase def test_absolute_pathed_layout @controller = AbsolutePathLayoutController.new - get :hello + assert_deprecated do + get :hello + end assert_equal "layout_test.erb hello.erb", @response.body.strip end end diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb index 52c3c54d96..c8ce7366d1 100644 --- a/actionview/test/actionpack/controller/render_test.rb +++ b/actionview/test/actionpack/controller/render_test.rb @@ -872,48 +872,64 @@ class RenderTest < ActionController::TestCase # :ported: def test_render_file_with_instance_variables - get :render_file_with_instance_variables + assert_deprecated do + get :render_file_with_instance_variables + end assert_equal "The secret is in the sauce\n", @response.body end def test_render_file - get :hello_world_file + assert_deprecated do + get :hello_world_file + end assert_equal "Hello world!", @response.body end # :ported: def test_render_file_not_using_full_path - get :render_file_not_using_full_path + assert_deprecated do + get :render_file_not_using_full_path + end assert_equal "The secret is in the sauce\n", @response.body end # :ported: def test_render_file_not_using_full_path_with_dot_in_path - get :render_file_not_using_full_path_with_dot_in_path + assert_deprecated do + get :render_file_not_using_full_path_with_dot_in_path + end assert_equal "The secret is in the sauce\n", @response.body end # :ported: def test_render_file_using_pathname - get :render_file_using_pathname + assert_deprecated do + get :render_file_using_pathname + end assert_equal "The secret is in the sauce\n", @response.body end # :ported: def test_render_file_with_locals - get :render_file_with_locals + assert_deprecated do + get :render_file_with_locals + end assert_equal "The secret is in the sauce\n", @response.body end # :ported: def test_render_file_as_string_with_locals - get :render_file_as_string_with_locals + assert_deprecated do + get :render_file_as_string_with_locals + end assert_equal "The secret is in the sauce\n", @response.body end # :assessed: def test_render_file_from_template - get :render_file_from_template + assert_deprecated do + get :render_file_from_template + end assert_equal "The secret is in the sauce\n", @response.body end @@ -1133,11 +1149,19 @@ class RenderTest < ActionController::TestCase end def test_bad_render_to_string_still_throws_exception - assert_raise(ActionView::MissingTemplate) { get :render_to_string_with_exception } + assert_deprecated do + assert_raise(ActionView::MissingTemplate) do + get :render_to_string_with_exception + end + end end def test_render_to_string_that_throws_caught_exception_doesnt_break_assigns - assert_nothing_raised { get :render_to_string_with_caught_exception } + assert_deprecated do + assert_nothing_raised do + get :render_to_string_with_caught_exception + end + end assert_equal "i'm before the render", @controller.instance_variable_get(:@before) assert_equal "i'm after the render", @controller.instance_variable_get(:@after) end diff --git a/actionview/test/fixtures/actionpack/test/hello.builder b/actionview/test/fixtures/actionpack/test/hello.builder index b8ab17ad5b..4c34ee85f0 100644 --- a/actionview/test/fixtures/actionpack/test/hello.builder +++ b/actionview/test/fixtures/actionpack/test/hello.builder @@ -1,4 +1,4 @@ xml.html do xml.p "Hello #{@name}" - xml << render(file: "test/greeting") + xml << render(template: "test/greeting") end diff --git a/actionview/test/fixtures/test/hello.builder b/actionview/test/fixtures/test/hello.builder index b8ab17ad5b..4c34ee85f0 100644 --- a/actionview/test/fixtures/test/hello.builder +++ b/actionview/test/fixtures/test/hello.builder @@ -1,4 +1,4 @@ xml.html do xml.p "Hello #{@name}" - xml << render(file: "test/greeting") + xml << render(template: "test/greeting") end diff --git a/actionview/test/fixtures/test/layout_render_file.erb b/actionview/test/fixtures/test/layout_render_file.erb index 2f8e921c5f..0477743dc4 100644 --- a/actionview/test/fixtures/test/layout_render_file.erb +++ b/actionview/test/fixtures/test/layout_render_file.erb @@ -1,2 +1,2 @@ <% content_for :title do %>title<% end -%> -<%= render :file => 'layouts/yield' -%>
\ No newline at end of file +<%= render template: 'layouts/yield' -%> diff --git a/actionview/test/fixtures/test/syntax_error.html.erb b/actionview/test/fixtures/test/syntax_error.html.erb new file mode 100644 index 0000000000..4004a2b187 --- /dev/null +++ b/actionview/test/fixtures/test/syntax_error.html.erb @@ -0,0 +1,4 @@ +<%= foo( + 1, + 2, +%> diff --git a/actionview/test/template/compiled_templates_test.rb b/actionview/test/template/compiled_templates_test.rb index 6375555bb4..d7f2e8ee07 100644 --- a/actionview/test/template/compiled_templates_test.rb +++ b/actionview/test/template/compiled_templates_test.rb @@ -24,7 +24,7 @@ class CompiledTemplatesTest < ActiveSupport::TestCase def test_template_with_ruby_keyword_locals assert_equal "The class is foo", - render(file: "test/render_file_with_ruby_keyword_locals", locals: { class: "foo" }) + render(template: "test/render_file_with_ruby_keyword_locals", locals: { class: "foo" }) end def test_template_with_invalid_identifier_locals @@ -34,7 +34,7 @@ class CompiledTemplatesTest < ActiveSupport::TestCase "d-a-s-h-e-s": "", "white space": "", } - assert_equal locals.inspect, render(file: "test/render_file_inspect_local_assigns", locals: locals) + assert_equal locals.inspect, render(template: "test/render_file_inspect_local_assigns", locals: locals) end def test_template_with_delegation_reserved_keywords @@ -44,36 +44,36 @@ class CompiledTemplatesTest < ActiveSupport::TestCase args: "three", block: "four", } - assert_equal "one two three four", render(file: "test/test_template_with_delegation_reserved_keywords", locals: locals) + assert_equal "one two three four", render(template: "test/test_template_with_delegation_reserved_keywords", locals: locals) end def test_template_with_unicode_identifier - assert_equal "๐", render(file: "test/render_file_unicode_local", locals: { ๐: "๐" }) + assert_equal "๐", render(template: "test/render_file_unicode_local", locals: { ๐: "๐" }) end def test_template_with_instance_variable_identifier - assert_equal "bar", render(file: "test/render_file_instance_variable", locals: { "@foo": "bar" }) + assert_equal "bar", render(template: "test/render_file_instance_variable", locals: { "@foo": "bar" }) end def test_template_gets_recompiled_when_using_different_keys_in_local_assigns - assert_equal "one", render(file: "test/render_file_with_locals_and_default") - assert_equal "two", render(file: "test/render_file_with_locals_and_default", locals: { secret: "two" }) + assert_equal "one", render(template: "test/render_file_with_locals_and_default") + assert_equal "two", render(template: "test/render_file_with_locals_and_default", locals: { secret: "two" }) end def test_template_changes_are_not_reflected_with_cached_templates - assert_equal "Hello world!", render(file: "test/hello_world") + assert_equal "Hello world!", render(template: "test/hello_world") modify_template "test/hello_world.erb", "Goodbye world!" do - assert_equal "Hello world!", render(file: "test/hello_world") + assert_equal "Hello world!", render(template: "test/hello_world") end - assert_equal "Hello world!", render(file: "test/hello_world") + assert_equal "Hello world!", render(template: "test/hello_world") end def test_template_changes_are_reflected_with_uncached_templates - assert_equal "Hello world!", render_without_cache(file: "test/hello_world") + assert_equal "Hello world!", render_without_cache(template: "test/hello_world") modify_template "test/hello_world.erb", "Goodbye world!" do - assert_equal "Goodbye world!", render_without_cache(file: "test/hello_world") + assert_equal "Goodbye world!", render_without_cache(template: "test/hello_world") end - assert_equal "Hello world!", render_without_cache(file: "test/hello_world") + assert_equal "Hello world!", render_without_cache(template: "test/hello_world") end private diff --git a/actionview/test/template/log_subscriber_test.rb b/actionview/test/template/log_subscriber_test.rb index 85735139c1..8b160a7336 100644 --- a/actionview/test/template/log_subscriber_test.rb +++ b/actionview/test/template/log_subscriber_test.rb @@ -51,9 +51,20 @@ class AVLogSubscriberTest < ActiveSupport::TestCase def @view.combined_fragment_cache_key(*); "ahoy `controller` dependency"; end end + def test_render_template_template + Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do + @view.render(template: "test/hello_world") + wait + + assert_equal 2, @logger.logged(:info).size + assert_match(/Rendering test\/hello_world\.erb/, @logger.logged(:info).first) + assert_match(/Rendered test\/hello_world\.erb/, @logger.logged(:info).last) + end + end + def test_render_file_template Rails.stub(:root, File.expand_path(FIXTURE_LOAD_PATH)) do - @view.render(file: "test/hello_world") + @view.render(file: "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") wait assert_equal 2, @logger.logged(:info).size diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb index 1f6dbfc4a5..15c41051de 100644 --- a/actionview/test/template/render_test.rb +++ b/actionview/test/template/render_test.rb @@ -53,20 +53,26 @@ module RenderTestCases assert_match(/You invoked render but did not give any of (.+) option\./, e.message) end + def test_render_template + assert_equal "Hello world!", @view.render(template: "test/hello_world") + end + + def test_render_file - assert_equal "Hello world!", @view.render(file: "test/hello_world") + assert_equal "Hello world!", assert_deprecated { @view.render(file: "test/hello_world") } end # Test if :formats, :locale etc. options are passed correctly to the resolvers. def test_render_file_with_format - assert_match "<h1>No Comment</h1>", @view.render(file: "comments/empty", formats: [:html]) - assert_match "<error>No Comment</error>", @view.render(file: "comments/empty", formats: [:xml]) - assert_match "<error>No Comment</error>", @view.render(file: "comments/empty", formats: :xml) + assert_match "<h1>No Comment</h1>", assert_deprecated { @view.render(file: "comments/empty", formats: [:html]) } + assert_match "<error>No Comment</error>", assert_deprecated { @view.render(file: "comments/empty", formats: [:xml]) } + assert_match "<error>No Comment</error>", assert_deprecated { @view.render(file: "comments/empty", formats: :xml) } end def test_render_template_with_format assert_match "<h1>No Comment</h1>", @view.render(template: "comments/empty", formats: [:html]) assert_match "<error>No Comment</error>", @view.render(template: "comments/empty", formats: [:xml]) + assert_match "<error>No Comment</error>", @view.render(template: "comments/empty", formats: :xml) end def test_render_partial_implicitly_use_format_of_the_rendered_template @@ -93,8 +99,8 @@ module RenderTestCases end def test_render_file_with_locale - assert_equal "<h1>Kein Kommentar</h1>", @view.render(file: "comments/empty", locale: [:de]) - assert_equal "<h1>Kein Kommentar</h1>", @view.render(file: "comments/empty", locale: :de) + assert_equal "<h1>Kein Kommentar</h1>", assert_deprecated { @view.render(file: "comments/empty", locale: [:de]) } + assert_equal "<h1>Kein Kommentar</h1>", assert_deprecated { @view.render(file: "comments/empty", locale: :de) } end def test_render_template_with_locale @@ -106,8 +112,8 @@ module RenderTestCases end def test_render_file_with_handlers - assert_equal "<h1>No Comment</h1>\n", @view.render(file: "comments/empty", handlers: [:builder]) - assert_equal "<h1>No Comment</h1>\n", @view.render(file: "comments/empty", handlers: :builder) + assert_equal "<h1>No Comment</h1>\n", assert_deprecated { @view.render(file: "comments/empty", handlers: [:builder]) } + assert_equal "<h1>No Comment</h1>\n", assert_deprecated { @view.render(file: "comments/empty", handlers: :builder) } end def test_render_template_with_handlers @@ -124,7 +130,7 @@ module RenderTestCases def test_render_raw_is_html_safe_and_does_not_escape_output buffer = ActiveSupport::SafeBuffer.new - buffer << @view.render(file: "plain_text") + buffer << @view.render(template: "plain_text") assert_equal true, buffer.html_safe? assert_equal buffer, "<%= hello_world %>\n" end @@ -137,40 +143,45 @@ module RenderTestCases assert_equal "4", @view.render(inline: "(2**2).to_s", type: :ruby) end - def test_render_file_with_localization_on_context_level + def test_render_template_with_localization_on_context_level old_locale, @view.locale = @view.locale, :da - assert_equal "Hey verden", @view.render(file: "test/hello_world") + assert_equal "Hey verden", @view.render(template: "test/hello_world") ensure @view.locale = old_locale end - def test_render_file_with_dashed_locale + def test_render_template_with_dashed_locale old_locale, @view.locale = @view.locale, :"pt-BR" - assert_equal "Ola mundo", @view.render(file: "test/hello_world") + assert_equal "Ola mundo", @view.render(template: "test/hello_world") ensure @view.locale = old_locale end - def test_render_file_at_top_level - assert_equal "Elastica", @view.render(file: "/shared") + def test_render_template_at_top_level + assert_equal "Elastica", @view.render(template: "/shared") end - def test_render_file_with_full_path + def test_render_file_with_full_path_no_extension template_path = File.expand_path("../fixtures/test/hello_world", __dir__) + assert_equal "Hello world!", assert_deprecated { @view.render(file: template_path) } + end + + def test_render_file_with_full_path + template_path = File.expand_path("../fixtures/test/hello_world.erb", __dir__) assert_equal "Hello world!", @view.render(file: template_path) end def test_render_file_with_instance_variables - assert_equal "The secret is in the sauce\n", @view.render(file: "test/render_file_with_ivar") + assert_equal "The secret is in the sauce\n", assert_deprecated { @view.render(file: "test/render_file_with_ivar") } end def test_render_file_with_locals locals = { secret: "in the sauce" } - assert_equal "The secret is in the sauce\n", @view.render(file: "test/render_file_with_locals", locals: locals) + assert_equal "The secret is in the sauce\n", assert_deprecated { @view.render(file: "test/render_file_with_locals", locals: locals) } end def test_render_file_not_using_full_path_with_dot_in_path - assert_equal "The secret is in the sauce\n", @view.render(file: "test/dot.directory/render_file_with_ivar") + assert_equal "The secret is in the sauce\n", assert_deprecated { @view.render(file: "test/dot.directory/render_file_with_ivar") } end def test_render_partial_from_default @@ -258,18 +269,24 @@ module RenderTestCases "and is followed by any combination of letters, numbers and underscores.", e.message end + def test_render_template_with_syntax_error + e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/syntax_error") } + assert_match %r!syntax!, e.message + assert_equal "1: <%= foo(", e.annotated_source_code[0].strip + end + def test_render_partial_with_errors e = assert_raises(ActionView::Template::Error) { @view.render(partial: "test/raise") } assert_match %r!method.*doesnt_exist!, e.message assert_equal "", e.sub_template_message assert_equal "1", e.line_number - assert_equal "1: <%= doesnt_exist %>", e.annoted_source_code[0].strip + assert_equal "1: <%= doesnt_exist %>", e.annotated_source_code[0].strip assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name end def test_render_error_indentation e = assert_raises(ActionView::Template::Error) { @view.render(partial: "test/raise_indentation") } - error_lines = e.annoted_source_code + error_lines = e.annotated_source_code assert_match %r!error\shere!, e.message assert_equal "11", e.line_number assert_equal " 9: <p>Ninth paragraph</p>", error_lines.second @@ -285,11 +302,11 @@ module RenderTestCases end def test_render_file_with_errors - e = assert_raises(ActionView::Template::Error) { @view.render(file: File.expand_path("test/_raise", FIXTURE_LOAD_PATH)) } + e = assert_raises(ActionView::Template::Error) { assert_deprecated { @view.render(file: File.expand_path("test/_raise", FIXTURE_LOAD_PATH)) } } assert_match %r!method.*doesnt_exist!, e.message assert_equal "", e.sub_template_message assert_equal "1", e.line_number - assert_equal "1: <%= doesnt_exist %>", e.annoted_source_code[0].strip + assert_equal "1: <%= doesnt_exist %>", e.annotated_source_code[0].strip assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name end @@ -369,7 +386,7 @@ module RenderTestCases def test_without_compiled_method_container_is_deprecated view = ActionView::Base.with_view_paths(ActionController::Base.view_paths) assert_deprecated("ActionView::Base instances must implement `compiled_method_container`") do - assert_equal "Hello world!", view.render(file: "test/hello_world") + assert_equal "Hello world!", view.render(template: "test/hello_world") end end @@ -549,28 +566,28 @@ module RenderTestCases def test_render_ignores_templates_with_malformed_template_handlers %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name| assert File.exist?(File.expand_path("#{FIXTURE_LOAD_PATH}/test/malformed/#{name}~")), "Malformed file (#{name}~) which should be ignored does not exists" - assert_raises(ActionView::MissingTemplate) { @view.render(file: "test/malformed/#{name}") } + assert_raises(ActionView::MissingTemplate) { @view.render(template: "test/malformed/#{name}") } end end def test_render_with_layout assert_equal %(<title></title>\nHello world!\n), - @view.render(file: "test/hello_world", layout: "layouts/yield") + @view.render(template: "test/hello_world", layout: "layouts/yield") end def test_render_with_layout_which_has_render_inline assert_equal %(welcome\nHello world!\n), - @view.render(file: "test/hello_world", layout: "layouts/yield_with_render_inline_inside") + @view.render(template: "test/hello_world", layout: "layouts/yield_with_render_inline_inside") end def test_render_with_layout_which_renders_another_partial assert_equal %(partial html\nHello world!\n), - @view.render(file: "test/hello_world", layout: "layouts/yield_with_render_partial_inside") + @view.render(template: "test/hello_world", layout: "layouts/yield_with_render_partial_inside") end def test_render_partial_with_html_only_extension assert_equal %(<h1>partial html</h1>\nHello world!\n), - @view.render(file: "test/hello_world", layout: "layouts/render_partial_html") + @view.render(template: "test/hello_world", layout: "layouts/render_partial_html") end def test_render_layout_with_block_and_yield @@ -625,17 +642,17 @@ module RenderTestCases def test_render_with_nested_layout assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n), - @view.render(file: "test/nested_layout", layout: "layouts/yield") + @view.render(template: "test/nested_layout", layout: "layouts/yield") end def test_render_with_file_in_layout assert_equal %(\n<title>title</title>\n\n), - @view.render(file: "test/layout_render_file") + @view.render(template: "test/layout_render_file") end def test_render_layout_with_object assert_equal %(<title>David</title>), - @view.render(file: "test/layout_render_object") + @view.render(template: "test/layout_render_object") end def test_render_with_passing_couple_extensions_to_one_register_template_handler_function_call @@ -687,7 +704,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_magic_comment with_external_encoding Encoding::ASCII_8BIT do - result = @view.render(file: "test/utf8_magic", formats: [:html], layouts: "layouts/yield") + result = @view.render(template: "test/utf8_magic", formats: [:html], layouts: "layouts/yield") assert_equal Encoding::UTF_8, result.encoding assert_equal "\nะ ัััะบะธะน \nัะตะบัั\n\nUTF-8\nUTF-8\nUTF-8\n", result end @@ -695,7 +712,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_default_external_encoding with_external_encoding Encoding::UTF_8 do - result = @view.render(file: "test/utf8", formats: [:html], layouts: "layouts/yield") + result = @view.render(template: "test/utf8", formats: [:html], layouts: "layouts/yield") assert_equal Encoding::UTF_8, result.encoding assert_equal "ะ ัััะบะธะน ัะตะบัั\n\nUTF-8\nUTF-8\nUTF-8\n", result end @@ -703,14 +720,14 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_incompatible_external_encoding with_external_encoding Encoding::SHIFT_JIS do - e = assert_raises(ActionView::Template::Error) { @view.render(file: "test/utf8", formats: [:html], layouts: "layouts/yield") } + e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/utf8", formats: [:html], layouts: "layouts/yield") } assert_match "Your template was not saved as valid Shift_JIS", e.cause.message end end def test_render_utf8_template_with_partial_with_incompatible_encoding with_external_encoding Encoding::SHIFT_JIS do - e = assert_raises(ActionView::Template::Error) { @view.render(file: "test/utf8_magic_with_bare_partial", formats: [:html], layouts: "layouts/yield") } + e = assert_raises(ActionView::Template::Error) { @view.render(template: "test/utf8_magic_with_bare_partial", formats: [:html], layouts: "layouts/yield") } assert_match "Your template was not saved as valid Shift_JIS", e.cause.message end end diff --git a/actionview/test/template/resolver_patterns_test.rb b/actionview/test/template/resolver_patterns_test.rb index 8122de779f..22815c8dbe 100644 --- a/actionview/test/template/resolver_patterns_test.rb +++ b/actionview/test/template/resolver_patterns_test.rb @@ -6,7 +6,10 @@ class ResolverPatternsTest < ActiveSupport::TestCase def setup path = File.expand_path("../fixtures", __dir__) pattern = ":prefix/{:formats/,}:action{.:formats,}{+:variants,}{.:handlers,}" - @resolver = ActionView::FileSystemResolver.new(path, pattern) + + assert_deprecated do + @resolver = ActionView::FileSystemResolver.new(path, pattern) + end end def test_should_return_empty_list_for_unknown_path diff --git a/actionview/test/template/streaming_render_test.rb b/actionview/test/template/streaming_render_test.rb index a5b59a700e..a5e673e71e 100644 --- a/actionview/test/template/streaming_render_test.rb +++ b/actionview/test/template/streaming_render_test.rb @@ -47,12 +47,12 @@ class FiberedTest < SetupFiberedBase end def test_render_file - assert_equal "Hello world!", buffered_render(file: "test/hello_world") + assert_equal "Hello world!", assert_deprecated { buffered_render(file: "test/hello_world") } end def test_render_file_with_locals locals = { secret: "in the sauce" } - assert_equal "The secret is in the sauce\n", buffered_render(file: "test/render_file_with_locals", locals: locals) + assert_equal "The secret is in the sauce\n", assert_deprecated { buffered_render(file: "test/render_file_with_locals", locals: locals) } end def test_render_partial diff --git a/actionview/test/template/test_case_test.rb b/actionview/test/template/test_case_test.rb index c89aff9c9d..0b2a2a9911 100644 --- a/actionview/test/template/test_case_test.rb +++ b/actionview/test/template/test_case_test.rb @@ -284,7 +284,7 @@ module ActionView @controller.controller_path = "test" @customers = [DeveloperStruct.new("Eloy"), DeveloperStruct.new("Manfred")] - assert_match(/Hello: EloyHello: Manfred/, render(file: "test/list")) + assert_match(/Hello: EloyHello: Manfred/, render(template: "test/list")) end test "is able to render partials from templates and also use instance variables after view has been referenced" do @@ -293,7 +293,7 @@ module ActionView view @customers = [DeveloperStruct.new("Eloy"), DeveloperStruct.new("Manfred")] - assert_match(/Hello: EloyHello: Manfred/, render(file: "test/list")) + assert_match(/Hello: EloyHello: Manfred/, render(template: "test/list")) end test "is able to use helpers that depend on the view flow" do diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb index 23fc9850c4..9afdc3c68f 100644 --- a/actionview/test/template/translation_helper_test.rb +++ b/actionview/test/template/translation_helper_test.rb @@ -127,20 +127,20 @@ class TranslationHelperTest < ActiveSupport::TestCase end def test_finds_translation_scoped_by_partial - assert_equal "Foo", view.render(file: "translations/templates/found").strip + assert_equal "Foo", view.render(template: "translations/templates/found").strip end def test_finds_array_of_translations_scoped_by_partial - assert_equal "Foo Bar", @view.render(file: "translations/templates/array").strip + assert_equal "Foo Bar", @view.render(template: "translations/templates/array").strip end def test_default_lookup_scoped_by_partial - assert_equal "Foo", view.render(file: "translations/templates/default").strip + assert_equal "Foo", view.render(template: "translations/templates/default").strip end def test_missing_translation_scoped_by_partial expected = '<span class="translation_missing" title="translation missing: en.translations.templates.missing.missing">Missing</span>' - assert_equal expected, view.render(file: "translations/templates/missing").strip + assert_equal expected, view.render(template: "translations/templates/missing").strip end def test_translate_does_not_mark_plain_text_as_safe_html |