From ddd85ef9c6a6297a8ff28816d907bbbf2eae5856 Mon Sep 17 00:00:00 2001 From: artemave Date: Fri, 17 Sep 2010 20:39:14 +0000 Subject: #948 template_inheritance --- actionpack/lib/abstract_controller/layouts.rb | 4 +- actionpack/lib/abstract_controller/rendering.rb | 16 ++++++-- .../lib/action_controller/metal/implicit_render.rb | 4 +- actionpack/lib/action_view/lookup_context.rb | 31 ++++++++++------ actionpack/lib/action_view/path_set.rb | 16 +++++--- .../lib/action_view/renderer/partial_renderer.rb | 4 +- .../lib/action_view/renderer/template_renderer.rb | 4 +- actionpack/lib/action_view/testing/resolvers.rb | 6 ++- .../test/abstract/abstract_controller_test.rb | 14 +++---- actionpack/test/abstract/render_test.rb | 4 +- .../controller/new_base/render_partial_test.rb | 25 ++++++++++++- actionpack/test/controller/new_base/render_test.rb | 43 +++++++++++++++++++++- 12 files changed, 129 insertions(+), 42 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 606f7eedec..4ee54474cc 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -265,11 +265,11 @@ module AbstractController raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil" when nil if name - _prefix = "layouts" unless _implied_layout_name =~ /\blayouts/ + _prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"] self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 def _layout - if template_exists?("#{_implied_layout_name}", #{_prefix.inspect}) + if template_exists?("#{_implied_layout_name}", #{_prefixes.inspect}) "#{_implied_layout_name}" else super diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 91b75273fa..06f4441609 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -114,9 +114,17 @@ module AbstractController view_context.render(options) end - # The prefix used in render "foo" shortcuts. - def _prefix - controller_path + # The prefixes used in render "foo" shortcuts. + def _prefixes + prefixes = [controller_path] + parent_controller = self.class.superclass + + until parent_controller.abstract? + prefixes << parent_controller.controller_path + parent_controller = parent_controller.superclass + end + + prefixes end private @@ -156,7 +164,7 @@ module AbstractController end if (options.keys & [:partial, :file, :template, :once]).empty? - options[:prefix] ||= _prefix + options[:prefixes] ||= _prefixes end options[:template] ||= (options[:action] || action_name).to_s diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb index 282dcf66b3..cfa7004048 100644 --- a/actionpack/lib/action_controller/metal/implicit_render.rb +++ b/actionpack/lib/action_controller/metal/implicit_render.rb @@ -12,10 +12,10 @@ module ActionController def method_for_action(action_name) super || begin - if template_exists?(action_name.to_s, _prefix) + if template_exists?(action_name.to_s, _prefixes) "default_render" end end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index d524c68450..14cccd88f0 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -78,17 +78,17 @@ module ActionView @view_paths = ActionView::Base.process_view_paths(paths) end - def find(name, prefix = nil, partial = false, keys = []) - @view_paths.find(*args_for_lookup(name, prefix, partial, keys)) + def find(name, prefixes = [], partial = false, keys = []) + @view_paths.find(*args_for_lookup(name, prefixes, partial, keys)) end alias :find_template :find - def find_all(name, prefix = nil, partial = false, keys = []) - @view_paths.find_all(*args_for_lookup(name, prefix, partial, keys)) + def find_all(name, prefixes = [], partial = false, keys = []) + @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys)) end - def exists?(name, prefix = nil, partial = false, keys = []) - @view_paths.exists?(*args_for_lookup(name, prefix, partial, keys)) + def exists?(name, prefixes = [], partial = false, keys = []) + @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys)) end alias :template_exists? :exists? @@ -107,18 +107,25 @@ module ActionView protected - def args_for_lookup(name, prefix, partial, keys) #:nodoc: - name, prefix = normalize_name(name, prefix) - [name, prefix, partial || false, @details, details_key, keys] + def args_for_lookup(name, prefixes, partial, keys) #:nodoc: + name, prefixes = normalize_name(name, prefixes) + [name, prefixes, partial || false, @details, details_key, keys] end # Support legacy foo.erb names even though we now ignore .erb # as well as incorrectly putting part of the path in the template # name instead of the prefix. - def normalize_name(name, prefix) #:nodoc: + def normalize_name(name, prefixes) #:nodoc: name = name.to_s.gsub(handlers_regexp, '') parts = name.split('/') - return parts.pop, [prefix, *parts].compact.join("/") + name = parts.pop + prx = if not prefixes or prefixes.empty? + [parts.compact.join('/')] + else + prefixes.map {|prefix| [prefix, *parts].compact.join('/') } + end + + return name, prx end def default_handlers #:nodoc: @@ -237,4 +244,4 @@ module ActionView include Details include ViewPaths end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index fa35120a0d..a7078b8232 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -11,15 +11,19 @@ module ActionView #:nodoc: end def find(*args) - find_all(*args).first || raise(MissingTemplate.new(self, "#{args[1]}/#{args[0]}", args[3], args[2])) + template = find_all(*args).first + template or raise MissingTemplate.new(self, "{#{args[1].join(',')},}/#{args[0]}", args[3], args[2]) end - def find_all(*args) - each do |resolver| - templates = resolver.find_all(*args) - return templates unless templates.empty? + def find_all(path, prefixes = [], *args) + templates = [] + prefixes.each do |prefix| + each do |resolver| + templates << resolver.find_all(path, prefix, *args) + end + # return templates unless templates.flatten!.empty? XXX this was original behavior; turns this method into find_some, but probably makes it faster end - [] + templates.flatten end def exists?(*args) diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 317479ad4c..e83f7be610 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -111,8 +111,8 @@ module ActionView end def find_template(path=@path, locals=@locals.keys) - prefix = @view.controller_prefix unless path.include?(?/) - @lookup_context.find_template(path, prefix, true, locals) + prefixes = path.include?(?/) ? [] : @view.controller._prefixes + @lookup_context.find_template(path, prefixes, true, locals) end def collection_with_template diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb index ece3f621b6..4a0bc503d3 100644 --- a/actionpack/lib/action_view/renderer/template_renderer.rb +++ b/actionpack/lib/action_view/renderer/template_renderer.rb @@ -43,13 +43,13 @@ module ActionView if options.key?(:text) Template::Text.new(options[:text], formats.try(:first)) elsif options.key?(:file) - with_fallbacks { find_template(options[:file], options[:prefix], false, keys) } + with_fallbacks { find_template(options[:file], [], false, keys) } elsif options.key?(:inline) handler = Template.handler_for_extension(options[:type] || "erb") Template.new(options[:inline], "inline template", handler, :locals => keys) elsif options.key?(:template) options[:template].respond_to?(:render) ? - options[:template] : find_template(options[:template], options[:prefix], false, keys) + options[:template] : find_template(options[:template], options[:prefixes], false, keys) end end diff --git a/actionpack/lib/action_view/testing/resolvers.rb b/actionpack/lib/action_view/testing/resolvers.rb index 55583096e0..5c5cab7c7d 100644 --- a/actionpack/lib/action_view/testing/resolvers.rb +++ b/actionpack/lib/action_view/testing/resolvers.rb @@ -13,7 +13,11 @@ module ActionView #:nodoc: @hash = hash end - private + def to_s + @hash.keys.join(', ') + end + + private def query(path, exts, formats) query = "" diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb index 19855490b4..981c023d38 100644 --- a/actionpack/test/abstract/abstract_controller_test.rb +++ b/actionpack/test/abstract/abstract_controller_test.rb @@ -30,14 +30,14 @@ module AbstractController class RenderingController < AbstractController::Base include ::AbstractController::Rendering - def _prefix() end + def _prefixes + [] + end def render(options = {}) if options.is_a?(String) options = {:_template_name => options} end - - options[:_prefix] = _prefix super end @@ -116,8 +116,8 @@ module AbstractController name.underscore end - def _prefix - self.class.prefix + def _prefixes + [self.class.prefix] end end @@ -157,10 +157,10 @@ module AbstractController private def self.layout(formats) begin - find_template(name.underscore, {:formats => formats}, :_prefix => "layouts") + find_template(name.underscore, {:formats => formats}, :_prefixes => ["layouts"]) rescue ActionView::MissingTemplate begin - find_template("application", {:formats => formats}, :_prefix => "layouts") + find_template("application", {:formats => formats}, :_prefixes => ["layouts"]) rescue ActionView::MissingTemplate end end diff --git a/actionpack/test/abstract/render_test.rb b/actionpack/test/abstract/render_test.rb index 25dc8bd804..b9293d1241 100644 --- a/actionpack/test/abstract/render_test.rb +++ b/actionpack/test/abstract/render_test.rb @@ -6,8 +6,8 @@ module AbstractController class ControllerRenderer < AbstractController::Base include AbstractController::Rendering - def _prefix - "renderer" + def _prefixes + %w[renderer] end self.view_paths = [ActionView::FixtureResolver.new( diff --git a/actionpack/test/controller/new_base/render_partial_test.rb b/actionpack/test/controller/new_base/render_partial_test.rb index d800ea264d..83b0d039ad 100644 --- a/actionpack/test/controller/new_base/render_partial_test.rb +++ b/actionpack/test/controller/new_base/render_partial_test.rb @@ -9,7 +9,10 @@ module RenderPartial "render_partial/basic/basic.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'basic' %><%= @test_unchanged %>", "render_partial/basic/with_json.html.erb" => "<%= render 'with_json.json' %>", "render_partial/basic/_with_json.json.erb" => "<%= render 'final' %>", - "render_partial/basic/_final.json.erb" => "{ final: json }" + "render_partial/basic/_final.json.erb" => "{ final: json }", + "render_partial/basic/overriden.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'overriden' %><%= @test_unchanged %>", + "render_partial/basic/_overriden.html.erb" => "ParentPartial!", + "render_partial/child/_overriden.html.erb" => "OverridenPartial!" )] def html_with_json_inside_json @@ -20,7 +23,13 @@ module RenderPartial @test_unchanged = 'hello' render :action => "basic" end + + def overriden + @test_unchanged = 'hello' + end end + + class ChildController < BasicController; end class TestPartial < Rack::TestCase testing BasicController @@ -37,4 +46,18 @@ module RenderPartial end end + class TestInheritedPartial < Rack::TestCase + testing ChildController + + test "partial from parent controller gets picked if missing in child one" do + get :changing + assert_response("goodbyeBasicPartial!goodbye") + end + + test "partial from child controller gets picked" do + get :overriden + assert_response("goodbyeOverridenPartial!goodbye") + end + end + end diff --git a/actionpack/test/controller/new_base/render_test.rb b/actionpack/test/controller/new_base/render_test.rb index df97a2725b..a520934c5b 100644 --- a/actionpack/test/controller/new_base/render_test.rb +++ b/actionpack/test/controller/new_base/render_test.rb @@ -6,7 +6,11 @@ module Render "render/blank_render/index.html.erb" => "Hello world!", "render/blank_render/access_request.html.erb" => "The request: <%= request.method.to_s.upcase %>", "render/blank_render/access_action_name.html.erb" => "Action Name: <%= action_name %>", - "render/blank_render/access_controller_name.html.erb" => "Controller Name: <%= controller_name %>" + "render/blank_render/access_controller_name.html.erb" => "Controller Name: <%= controller_name %>", + "render/blank_render/overriden_with_own_view_paths_appended.html.erb" => "parent content", + "render/blank_render/overriden_with_own_view_paths_prepended.html.erb" => "parent content", + "render/blank_render/overriden.html.erb" => "parent content", + "render/child_render/overriden.html.erb" => "child content" )] def index @@ -21,6 +25,15 @@ module Render render :action => "access_action_name" end + def overriden_with_own_view_paths_appended + end + + def overriden_with_own_view_paths_prepended + end + + def overriden + end + private def secretz @@ -35,6 +48,11 @@ module Render end end + class ChildRenderController < BlankRenderController + append_view_path ActionView::FixtureResolver.new("render/child_render/overriden_with_own_view_paths_appended.html.erb" => "child content") + prepend_view_path ActionView::FixtureResolver.new("render/child_render/overriden_with_own_view_paths_prepended.html.erb" => "child content") + end + class RenderTest < Rack::TestCase test "render with blank" do with_routing do |set| @@ -94,4 +112,27 @@ module Render assert_body "Controller Name: blank_render" end end + + class TestViewInheritance < Rack::TestCase + test "Template from child controller gets picked over parent one" do + get "/render/child_render/overriden" + assert_body "child content" + end + + test "Template from child controller with custom view_paths prepended gets picked over parent one" do + get "/render/child_render/overriden_with_own_view_paths_prepended" + assert_body "child content" + end + + test "Template from child controller with custom view_paths appended gets picked over parent one" do + get "/render/child_render/overriden_with_own_view_paths_appended" + assert_body "child content" + end + + test "Template from parent controller gets picked if missing in child controller" do + get "/render/child_render/index" + assert_body "Hello world!" + end + end + end -- cgit v1.2.3