Permalink
Browse files

Change render to support any hash keys in locals

this lets you pass ruby keywords to templates:

    <%= render 'example', class: "cool" %>

    <%= render 'example', "spaces are" => "a-ok" %>

    <%= render 'example', Foo: "bar" %>

Previously you'd see confusing syntax errors like this:

    SyntaxError (.../_example.html.erb:1: syntax error, unexpected '='

Now you can reference invalid identifiers through local_assigns.

If you try to use an invalid keyword (e.g. class) in your template, you
get a syntax error on the line where you use it.
  • Loading branch information...
schpet committed Sep 30, 2016
1 parent 72f97e2 commit f9960f2d74b510e0d994d49377cec36301f7e7f0
@@ -1,3 +1,21 @@
* Render now accepts any keys for locals, including reserved words

Only locals with valid variable names get set directly. Others
will still be available in local_assigns.

Example of render with reserved words:

```erb
<%= render "example", class: "text-center", message: "Hello world!" %>
<!-- _example.html.erb: -->
<%= tag.div class: local_assigns[:class] do %>
<p><%= message %></p>
<% end %>
```

*Peter Schilling*, *Matthew Draper*

* Show cache hits and misses when rendering partials.

Partials using the `cache` helper will show whether a render hit or missed
@@ -1,5 +1,6 @@
require "active_support/core_ext/object/try"
require "active_support/core_ext/kernel/singleton_class"
require "active_support/core_ext/module/delegation"
require "thread"

module ActionView
@@ -324,8 +325,13 @@ def handle_render_error(view, e) #:nodoc:
end

def locals_code #:nodoc:
# Only locals with valid variable names get set directly. Others will
# still be available in local_assigns.
locals = @locals.to_set - Module::DELEGATION_RESERVED_METHOD_NAMES
locals = locals.grep(/\A(?![A-Z0-9])(?:[[:alnum:]_]|[^\0-\177])+\z/)

# Double assign to suppress the dreaded 'assigned but unused variable' warning
@locals.each_with_object("") { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" }
locals.each_with_object("") { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" }
end

def method_name #:nodoc:
@@ -0,0 +1 @@
<%= local_assigns.inspect.html_safe %>
@@ -0,0 +1 @@
The class is <%= local_assigns[:class] %>
@@ -9,6 +9,25 @@ def test_template_with_nil_erb_return
assert_equal "This is nil: \n", render(template: "test/nil_return")
end

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" })
end

def test_template_with_invalid_identifier_locals
locals = {
foo: "bar",
Foo: "bar",
"d-a-s-h-e-s": "",
"white space": "",
}
assert_equal locals.inspect, render(file: "test/render_file_inspect_local_assigns", locals: locals)
end

def test_template_with_unicode_identifier
assert_equal "🎂", render(file: "test/render_file_unicode_local", locals: { 🎃: "🎂" })
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" })

0 comments on commit f9960f2

Please sign in to comment.