Changed the default of ActionView#render to assume partials instead of files when not given an options hash [DHH]

This commit is contained in:
David Heinemeier Hansson 2008-11-19 14:00:16 +01:00
parent 0c9f677e78
commit 130fe74d17
6 changed files with 87 additions and 22 deletions

View File

@ -1,5 +1,21 @@
*2.3.0/3.0*
* Changed the default of ActionView#render to assume partials instead of files when not given an options hash [DHH]. Examples:
# Instead of <%= render :partial => "account" %>
<%= render "account" %>
# Instead of <%= render :partial => "account", :locals => { :account => @buyer } %>
<%= render "account", :account => @buyer %>
# @account is an Account instance, so it uses the RecordIdentifier to replace
# <%= render :partial => "accounts/account", :locals => { :account => @account } %>
<%= render(@account) %>
# @posts is an array of Post instances, so it uses the RecordIdentifier to replace
# <%= render :partial => "posts/post", :collection => @posts %>
<%= render(@posts) %>
* Fixed RedCloth and BlueCloth shouldn't preload. Instead just assume that they're available if you want to use textilize and markdown and let autoload require them [DHH]

View File

@ -234,16 +234,21 @@ module ActionView #:nodoc:
@view_paths = self.class.process_view_paths(paths)
end
# Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
# The hash in <tt>local_assigns</tt> is made available as local variables.
# Returns the result of a render that's dictated by the options hash. The primary options are:
#
# * <tt>:partial</tt> - See ActionView::Partials.
# * <tt>:update</tt> - Calls update_page with the block given.
# * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
# * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
# * <tt>:text</tt> - Renders the text passed in out.
#
# If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
# as the locals hash.
def render(options = {}, local_assigns = {}, &block) #:nodoc:
local_assigns ||= {}
if options.is_a?(String)
render(:file => options, :locals => local_assigns)
elsif options == :update
update_page(&block)
elsif options.is_a?(Hash)
case options
when Hash
options = options.reverse_merge(:locals => {})
if options[:layout]
_render_with_layout(options, local_assigns, &block)
@ -256,6 +261,10 @@ module ActionView #:nodoc:
elsif options[:text]
options[:text]
end
when :update
update_page(&block)
else
render_partial(:partial => options, :locals => local_assigns)
end
end

View File

@ -46,6 +46,38 @@ module ActionView
#
# This will render the partial "advertisement/_ad.erb" regardless of which controller this is being called from.
#
# == Rendering objects with the RecordIdentifier
#
# Instead of explicitly naming the location of a partial, you can also let the RecordIdentifier do the work if
# you're following its conventions for RecordIdentifier#partial_path. Examples:
#
# # @account is an Account instance, so it uses the RecordIdentifier to replace
# # <%= render :partial => "accounts/account", :locals => { :account => @buyer } %>
# <%= render :partial => @account %>
#
# # @posts is an array of Post instances, so it uses the RecordIdentifier to replace
# # <%= render :partial => "posts/post", :collection => @posts %>
# <%= render :partial => @posts %>
#
# == Rendering the default case
#
# If you're not going to be using any of the options like collections or layouts, you can also use the short-hand
# defaults of render to render partials. Examples:
#
# # Instead of <%= render :partial => "account" %>
# <%= render "account" %>
#
# # Instead of <%= render :partial => "account", :locals => { :account => @buyer } %>
# <%= render "account", :account => @buyer %>
#
# # @account is an Account instance, so it uses the RecordIdentifier to replace
# # <%= render :partial => "accounts/account", :locals => { :account => @account } %>
# <%= render(@account) %>
#
# # @posts is an array of Post instances, so it uses the RecordIdentifier to replace
# # <%= render :partial => "posts/post", :collection => @posts %>
# <%= render(@posts) %>
#
# == Rendering partials with layouts
#
# Partials can have their own layouts applied to them. These layouts are different than the ones that are

View File

@ -1,4 +1,4 @@
xml.html do
xml.p "Hello #{@name}"
xml << render("test/greeting")
xml << render(:file => "test/greeting")
end

View File

@ -12,30 +12,30 @@ uses_mocha 'TestTemplateRecompilation' do
def test_template_gets_compiled
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", render("test/hello_world.erb")
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
assert_equal 1, @compiled_templates.instance_methods.size
end
def test_template_gets_recompiled_when_using_different_keys_in_local_assigns
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", render("test/hello_world.erb")
assert_equal "Hello world!", render("test/hello_world.erb", {:foo => "bar"})
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
assert_equal "Hello world!", render(:file => "test/hello_world.erb", :locals => {:foo => "bar"})
assert_equal 2, @compiled_templates.instance_methods.size
end
def test_compiled_template_will_not_be_recompiled_when_rendered_with_identical_local_assigns
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", render("test/hello_world.erb")
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
ActionView::Template.any_instance.expects(:compile!).never
assert_equal "Hello world!", render("test/hello_world.erb")
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
end
def test_compiled_template_will_always_be_recompiled_when_eager_loaded_templates_is_off
ActionView::PathSet::Path.expects(:eager_load_templates?).times(4).returns(false)
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", render("#{FIXTURE_LOAD_PATH}/test/hello_world.erb")
assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb")
ActionView::Template.any_instance.expects(:compile!).times(3)
3.times { assert_equal "Hello world!", render("#{FIXTURE_LOAD_PATH}/test/hello_world.erb") }
3.times { assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") }
assert_equal 1, @compiled_templates.instance_methods.size
end

View File

@ -8,7 +8,7 @@ class ViewRenderTest < Test::Unit::TestCase
end
def test_render_file
assert_equal "Hello world!", @view.render("test/hello_world.erb")
assert_equal "Hello world!", @view.render(:file => "test/hello_world.erb")
end
def test_render_file_not_using_full_path
@ -16,11 +16,11 @@ class ViewRenderTest < Test::Unit::TestCase
end
def test_render_file_without_specific_extension
assert_equal "Hello world!", @view.render("test/hello_world")
assert_equal "Hello world!", @view.render(:file => "test/hello_world")
end
def test_render_file_at_top_level
assert_equal 'Elastica', @view.render('/shared')
assert_equal 'Elastica', @view.render(:file => '/shared')
end
def test_render_file_with_full_path
@ -29,20 +29,20 @@ class ViewRenderTest < Test::Unit::TestCase
end
def test_render_file_with_instance_variables
assert_equal "The secret is in the sauce\n", @view.render("test/render_file_with_ivar.erb")
assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_ivar.erb")
end
def test_render_file_with_locals
locals = { :secret => 'in the sauce' }
assert_equal "The secret is in the sauce\n", @view.render("test/render_file_with_locals.erb", locals)
assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_locals.erb", :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("test/dot.directory/render_file_with_ivar")
assert_equal "The secret is in the sauce\n", @view.render(:file => "test/dot.directory/render_file_with_ivar")
end
def test_render_has_access_current_template
assert_equal "test/template.erb", @view.render("test/template.erb")
assert_equal "test/template.erb", @view.render(:file => "test/template.erb")
end
def test_render_update
@ -51,6 +51,10 @@ class ViewRenderTest < Test::Unit::TestCase
assert_equal 'alert("Hello, World!");', @view.render(:update) { |page| page.alert('Hello, World!') }
end
def test_render_partial_from_default
assert_equal "only partial", @view.render("test/partial_only")
end
def test_render_partial
assert_equal "only partial", @view.render(:partial => "test/partial_only")
end
@ -73,6 +77,10 @@ class ViewRenderTest < Test::Unit::TestCase
assert_equal "5", @view.render(:partial => "test/counter", :locals => { :counter_counter => 5 })
end
def test_render_partial_with_locals_from_default
assert_equal "only partial", @view.render("test/partial_only", :counter_counter => 5)
end
def test_render_partial_with_errors
@view.render(:partial => "test/raise")
flunk "Render did not raise TemplateError"