1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Allow layout fallback when using layout method

Rails will now use your default layout (such as "layouts/application") when you specify a layout with `:only` and `:except` condition, and those conditions fail.

For example, consider this snippet:

    class CarsController
      layout 'single_car', :only => :show
    end

Rails will use 'layouts/single_car' when a request comes in `:show` action, and use 'layouts/application' (or 'layouts/cars', if exists) when a request comes in for any other actions.
This commit is contained in:
Prem Sichanugrist 2011-12-06 21:05:56 -05:00
parent 0460b3a469
commit 18ceed201b
3 changed files with 94 additions and 27 deletions

View file

@ -1,5 +1,15 @@
## Rails 3.2.0 (unreleased) ##
* Rails will now use your default layout (such as "layouts/application") when you specify a layout with `:only` and `:except` condition, and those conditions fail. *Prem Sichanugrist*
For example, consider this snippet:
class CarsController
layout 'single_car', :only => :show
end
Rails will use 'layouts/single_car' when a request comes in `:show` action, and use 'layouts/application' (or 'layouts/cars', if exists) when a request comes in for any other actions.
* form_for with +:as+ option uses "#{action}_#{as}" as css class and id:
Before:

View file

@ -244,42 +244,51 @@ module AbstractController
def _write_layout_method
remove_possible_method(:_layout)
case defined?(@_layout) ? @_layout : nil
when String
self.class_eval %{def _layout; #{@_layout.inspect} end}, __FILE__, __LINE__
when Symbol
self.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
def _layout
prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
layout_definition = case defined?(@_layout) ? @_layout : nil
when String
@_layout.inspect
when Symbol
<<-RUBY
#{@_layout}.tap do |layout|
unless layout.is_a?(String) || !layout
raise ArgumentError, "Your layout method :#{@_layout} returned \#{layout}. It " \
"should have returned a String, false, or nil"
end
end
end
ruby_eval
when Proc
define_method :_layout_from_proc, &@_layout
self.class_eval %{def _layout; _layout_from_proc(self) end}, __FILE__, __LINE__
when false
self.class_eval %{def _layout; end}, __FILE__, __LINE__
when true
raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
when nil
if name
_prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def _layout
if template_exists?("#{_implied_layout_name}", #{_prefixes.inspect})
RUBY
when Proc
define_method :_layout_from_proc, &@_layout
"_layout_from_proc(self)"
when false
nil
when true
raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
when nil
if name
<<-RUBY
if template_exists?("#{_implied_layout_name}", #{prefixes.inspect})
"#{_implied_layout_name}"
else
super
end
end
RUBY
RUBY
end
end
end
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def _layout
if action_has_layout?
#{layout_definition}
elsif self.class.name
if template_exists?("#{_implied_layout_name}", #{prefixes.inspect})
"#{_implied_layout_name}"
else
super
end
end
end
RUBY
self.class_eval { private :_layout }
end
end
@ -337,7 +346,7 @@ module AbstractController
# * <tt>template</tt> - The template object for the default layout (or nil)
def _default_layout(require_layout = false)
begin
layout_name = _layout if action_has_layout?
layout_name = _layout
rescue NameError => e
raise e, "Could not render layout: #{e.message}"
end

View file

@ -141,6 +141,30 @@ module AbstractControllerTests
end
end
class WithOnlyConditional < WithStringImpliedChild
layout "overwrite", :only => :show
def index
render :template => ActionView::Template::Text.new("Hello index!")
end
def show
render :template => ActionView::Template::Text.new("Hello show!")
end
end
class WithExceptConditional < WithStringImpliedChild
layout "overwrite", :except => :show
def index
render :template => ActionView::Template::Text.new("Hello index!")
end
def show
render :template => ActionView::Template::Text.new("Hello show!")
end
end
class TestBase < ActiveSupport::TestCase
test "when no layout is specified, and no default is available, render without a layout" do
controller = Blank.new
@ -260,6 +284,30 @@ module AbstractControllerTests
end
end
end
test "when specify an :only option which match current action name" do
controller = WithOnlyConditional.new
controller.process(:show)
assert_equal "Overwrite Hello show!", controller.response_body
end
test "when specify an :only option which does not match current action name" do
controller = WithOnlyConditional.new
controller.process(:index)
assert_equal "With Implied Hello index!", controller.response_body
end
test "when specify an :except option which match current action name" do
controller = WithExceptConditional.new
controller.process(:show)
assert_equal "With Implied Hello show!", controller.response_body
end
test "when specify an :except option which does not match current action name" do
controller = WithExceptConditional.new
controller.process(:index)
assert_equal "Overwrite Hello index!", controller.response_body
end
end
end
end
end