Skip to content

Commit 9375e86

Browse files
authored
Merge pull request #31 from github/non-instance-syntax
Use render(MyComponent, foo: :bar) syntax
2 parents 42f4746 + 52ce0ba commit 9375e86

File tree

12 files changed

+117
-35
lines changed

12 files changed

+117
-35
lines changed

CHANGELOG.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
1-
* Components now inherit from ActionView::Component::base
1+
* The `render_component` test helper has been renamed to `render_inline`. `render_component` has been deprecated and will be removed in v2.0.0.
22

33
*Joel Hawksley*
44

5+
* Components are now rendered with `render MyComponent, foo: :bar` syntax. The existing `render MyComponent.new(foo: :bar)` syntax has been deprecated and will be removed in v2.0.0.
6+
7+
*Joel Hawksley*
8+
9+
# v1.1.0
10+
11+
* Components now inherit from ActionView::Component::Base
12+
13+
*Joel Hawksley*
14+
15+
# v1.0.1
16+
517
* Always recompile component templates outside production.
618

719
*Joel Hawksley, John Hawthorn*
20+
21+
# v1.0.0
22+
23+
This release extracts the `ActionView::Component` library from the GitHub application.
24+
25+
It will be published on RubyGems under the existing `actionview-component` gem name, as @chancancode has passed us ownership of the gem.

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
actionview-component (1.0.1)
4+
actionview-component (1.1.0)
55

66
GEM
77
remote: https://rubygems.org/

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ end
124124
We can render it in a view as:
125125

126126
```erb
127-
<%= render(TestComponent.new(title: "my title")) do %>
127+
<%= render(TestComponent, title: "my title") do %>
128128
Hello, World!
129129
<% end %>
130130
```
@@ -135,12 +135,24 @@ Which returns:
135135
<span title="my title">Hello, World!</span>
136136
```
137137

138+
##### Supported `render` syntaxes
139+
140+
Components can be rendered via:
141+
142+
`render(TestComponent, foo: :bar)`
143+
144+
`render(component: TestComponent, locals: { foo: :bar })`
145+
146+
The following syntax has been deprecated and will be removed in v2.0.0:
147+
148+
`render(TestComponent.new(foo: :bar)`
149+
138150
#### Error case
139151

140152
If the component is rendered with a blank title:
141153

142154
```erb
143-
<%= render(TestComponent.new(title: "")) do %>
155+
<%= render(TestComponent, title: "") do %>
144156
Hello, World!
145157
<% end %>
146158
```
@@ -151,7 +163,7 @@ An error will be raised:
151163

152164
### Testing
153165

154-
Components are unit tested directly. The `render_component` test helper renders a component and wraps the result in `Nokogiri.HTML`, allowing us to test the component above as:
166+
Components are unit tested directly. The `render_inline` test helper wraps the result in `Nokogiri.HTML`, allowing us to test the component above as:
155167

156168
```ruby
157169
require "action_view/component/test_helpers"
@@ -162,7 +174,7 @@ class MyComponentTest < Minitest::Test
162174
def test_render_component
163175
assert_equal(
164176
%(<span title="my title">Hello, World!</span>),
165-
render_component(TestComponent.new(title: "my title")) { "Hello, World!" }.css("span").to_html
177+
render_inline(TestComponent, title: "my title") { "Hello, World!" }.css("span").to_html
166178
)
167179
end
168180
end

lib/action_view/component/base.rb

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,28 @@
22

33
# Monkey patch ActionView::Base#render to support ActionView::Component
44
#
5-
# Upstreamed in https://github.com/rails/rails/pull/36388
6-
# Necessary for Rails versions < 6.1.0.alpha
5+
# A version of this monkey patch was upstreamed in https://github.com/rails/rails/pull/36388
6+
# We'll need to upstream an updated version of this eventually.
77
class ActionView::Base
88
module RenderMonkeyPatch
9-
def render(component, _ = nil, &block)
10-
return super unless component.respond_to?(:render_in)
11-
12-
component.render_in(self, &block)
9+
def render(options = {}, args = {}, &block)
10+
if options.respond_to?(:render_in)
11+
ActiveSupport::Deprecation.warn(
12+
"passing component instances to `render` has been deprecated and will be removed in v2.0.0. Use `render MyComponent, foo: :bar` instead."
13+
)
14+
15+
options.render_in(self, &block)
16+
elsif options.is_a?(Class) && options < ActionView::Component::Base
17+
options.new(args).render_in(self, &block)
18+
elsif options.is_a?(Hash) && options.has_key?(:component)
19+
options[:component].new(options[:locals]).render_in(self, &block)
20+
else
21+
super
22+
end
1323
end
1424
end
1525

16-
prepend RenderMonkeyPatch unless Rails::VERSION::MINOR > 0 && Rails::VERSION::MAJOR == 6
26+
prepend RenderMonkeyPatch
1727
end
1828

1929
module ActionView
@@ -42,7 +52,7 @@ class Base < ActionView::Base
4252
# <span title="<%= @title %>">Hello, <%= content %>!</span>
4353
#
4454
# In use:
45-
# <%= render MyComponent.new(title: "greeting") do %>world<% end %>
55+
# <%= render MyComponent, title: "greeting" do %>world<% end %>
4656
# returns:
4757
# <span title="greeting">Hello, world!</span>
4858
#

lib/action_view/component/test_helpers.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,16 @@
33
module ActionView
44
module Component
55
module TestHelpers
6-
def render_component(component, &block)
7-
Nokogiri::HTML(component.render_in(ApplicationController.new.view_context, &block))
6+
def render_inline(component, **args, &block)
7+
Nokogiri::HTML(ApplicationController.new.view_context.render(component, args, &block))
8+
end
9+
10+
def render_component(component, **args, &block)
11+
ActiveSupport::Deprecation.warn(
12+
"`render_component` has been deprecated in favor of `render_inline`, and will be removed in v2.0.0."
13+
)
14+
15+
render_inline(component, args, &block)
816
end
917
end
1018
end

test/action_view/component_test.rb

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,100 +6,120 @@ class ActionView::ComponentTest < Minitest::Test
66
include ActionView::Component::TestHelpers
77

88
def test_render_component
9-
result = render_component(MyComponent.new)
9+
result = render_inline(MyComponent)
10+
11+
assert_equal trim_result(result.css("div").first.to_html), "<div>hello,world!</div>"
12+
end
13+
14+
def test_render_component_with_old_helper
15+
result = render_component(MyComponent)
1016

1117
assert_equal trim_result(result.css("div").first.to_html), "<div>hello,world!</div>"
1218
end
1319

1420
def test_raises_error_when_sidecar_template_is_missing
1521
exception = assert_raises NotImplementedError do
16-
render_component(MissingTemplateComponent.new)
22+
render_inline(MissingTemplateComponent)
1723
end
1824

1925
assert_includes exception.message, "Could not find a template file for MissingTemplateComponent"
2026
end
2127

2228
def test_raises_error_when_more_then_one_sidecar_template_is_present
2329
error = assert_raises StandardError do
24-
render_component(TooManySidecarFilesComponent.new)
30+
render_inline(TooManySidecarFilesComponent)
2531
end
2632

2733
assert_includes error.message, "More than one template found for TooManySidecarFilesComponent."
2834
end
2935

3036
def test_raises_error_when_initializer_is_not_defined
3137
exception = assert_raises NotImplementedError do
32-
render_component(MissingInitializerComponent.new)
38+
render_inline(MissingInitializerComponent)
3339
end
3440

3541
assert_includes exception.message, "must implement #initialize"
3642
end
3743

3844
def test_checks_validations
3945
exception = assert_raises ActiveModel::ValidationError do
40-
render_component(WrapperComponent.new)
46+
render_inline(WrapperComponent)
4147
end
4248

4349
assert_includes exception.message, "Content can't be blank"
4450
end
4551

4652
def test_renders_content_from_block
47-
result = render_component(WrapperComponent.new) do
53+
result = render_inline(WrapperComponent) do
4854
"content"
4955
end
5056

5157
assert_equal trim_result(result.css("span").first.to_html), "<span>content</span>"
5258
end
5359

5460
def test_renders_slim_template
55-
result = render_component(SlimComponent.new(message: "bar")) { "foo" }
61+
result = render_inline(SlimComponent, message: "bar") { "foo" }
5662

5763
assert_includes result.text, "foo"
5864
assert_includes result.text, "bar"
5965
end
6066

6167
def test_renders_haml_template
62-
result = render_component(HamlComponent.new(message: "bar")) { "foo" }
68+
result = render_inline(HamlComponent, message: "bar") { "foo" }
6369

6470
assert_includes result.text, "foo"
6571
assert_includes result.text, "bar"
6672
end
6773

6874
def test_renders_erb_template
69-
result = render_component(ErbComponent.new(message: "bar")) { "foo" }
75+
result = render_inline(ErbComponent, message: "bar") { "foo" }
76+
77+
assert_includes result.text, "foo"
78+
assert_includes result.text, "bar"
79+
end
80+
81+
def test_renders_erb_template_with_old_syntax
82+
result = render_inline(ErbComponent.new(message: "bar")) { "foo" }
83+
84+
assert_includes result.text, "foo"
85+
assert_includes result.text, "bar"
86+
end
87+
88+
def test_renders_erb_template_with_hash_syntax
89+
result = render_inline(component: ErbComponent, locals: { message: "bar" }) { "foo" }
7090

7191
assert_includes result.text, "foo"
7292
assert_includes result.text, "bar"
7393
end
7494

7595
def test_renders_route_helper
76-
result = render_component(RouteComponent.new)
96+
result = render_inline(RouteComponent)
7797

7898
assert_includes result.text, "/"
7999
end
80100

81101
def test_template_changes_are_not_reflected_in_production
82102
ActionView::Base.cache_template_loading = true
83103

84-
assert_equal "<div>hello,world!</div>", render_component(MyComponent.new).css("div").first.to_html
104+
assert_equal "<div>hello,world!</div>", render_inline(MyComponent).css("div").first.to_html
85105

86106
modify_file "app/components/my_component.html.erb", "<div>Goodbye world!</div>" do
87-
assert_equal "<div>hello,world!</div>", render_component(MyComponent.new).css("div").first.to_html
107+
assert_equal "<div>hello,world!</div>", render_inline(MyComponent).css("div").first.to_html
88108
end
89109

90-
assert_equal "<div>hello,world!</div>", render_component(MyComponent.new).css("div").first.to_html
110+
assert_equal "<div>hello,world!</div>", render_inline(MyComponent).css("div").first.to_html
91111
end
92112

93113
def test_template_changes_are_reflected_outside_production
94114
ActionView::Base.cache_template_loading = false
95115

96-
assert_equal "<div>hello,world!</div>", render_component(MyComponent.new).css("div").first.to_html
116+
assert_equal "<div>hello,world!</div>", render_inline(MyComponent).css("div").first.to_html
97117

98118
modify_file "app/components/my_component.html.erb", "<div>Goodbye world!</div>" do
99-
assert_equal "<div>Goodbye world!</div>", render_component(MyComponent.new).css("div").first.to_html
119+
assert_equal "<div>Goodbye world!</div>", render_inline(MyComponent).css("div").first.to_html
100120
end
101121

102-
assert_equal "<div>hello,world!</div>", render_component(MyComponent.new).css("div").first.to_html
122+
assert_equal "<div>hello,world!</div>", render_inline(MyComponent).css("div").first.to_html
103123
end
104124

105125
private

test/action_view/integration_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,16 @@ class IntegrationTest < ActionDispatch::IntegrationTest
88
assert_response :success
99
assert_equal trim_result(response.body), "<span><div>Foobar</div></span>"
1010
end
11+
12+
test "rendering component in a view with component: syntax" do
13+
get "/component"
14+
assert_response :success
15+
assert_equal trim_result(response.body), "<span><div>Foobar</div></span>"
16+
end
17+
18+
test "rendering component in a view with deprecated syntax" do
19+
get "/deprecated"
20+
assert_response :success
21+
assert_equal trim_result(response.body), "<span><div>Foobar</div></span>"
22+
end
1123
end
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
# frozen_string_literal: true
22

33
class ApplicationController < ActionController::Base
4-
def index
5-
end
64
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<span><%= render component: ErbComponent, locals: { message: "bar" } do %>Foo<% end %></span>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<span><%= render ErbComponent.new(message: "bar") do %>Foo<% end %></span>

0 commit comments

Comments
 (0)