Skip to content

Commit

Permalink
Add render_parent helper method to avoid double-rendering hijinks (#1353
Browse files Browse the repository at this point in the history
)

* Add render_parent helper method to avoid double-rendering madness

* Add CHANGELOG entry

* Update docs/CHANGELOG.md

Co-authored-by: Joel Hawksley <joel@hawksley.org>

* Update docs/guide/templates.md

Co-authored-by: Joel Hawksley <joel@hawksley.org>

* Update docs/guide/templates.md

Co-authored-by: Joel Hawksley <joel@hawksley.org>

* Update docs/guide/templates.md

Co-authored-by: Joel Hawksley <joel@hawksley.org>

* Update lib/view_component/base.rb

Co-authored-by: Joel Hawksley <joel@hawksley.org>

* Update lib/view_component/base.rb

Co-authored-by: Joel Hawksley <joel@hawksley.org>

* Update lib/view_component/base.rb

Co-authored-by: Joel Hawksley <joel@hawksley.org>

* Update lib/view_component/base.rb

Co-authored-by: Joel Hawksley <joel@hawksley.org>

* Update lib/view_component/base.rb

Co-authored-by: Joel Hawksley <joel@hawksley.org>

Co-authored-by: Joel Hawksley <joel@hawksley.org>
  • Loading branch information
camertron and joelhawksley authored May 11, 2022
1 parent 2a35a19 commit 1ea088f
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ title: Changelog

## main

* Add `render_parent` convenience method to avoid confusion between `<%= super %>` and `<% super %>` in template code.

*Cameron Dutro*

* Add note about discouraging inheritance.

*Joel Hawksley*
Expand Down
11 changes: 11 additions & 0 deletions docs/guide/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,14 @@ Component subclasses inherit the parent component's template if they don't defin
class MyLinkComponent < LinkComponent
end
```

### Rendering parent templates

To render a parent component's template from a subclass, call `render_parent`:

```erb
<%# my_link_component.html.erb %>
<div class="base-component-template">
<% render_parent %>
</div>
```
14 changes: 14 additions & 0 deletions lib/view_component/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,20 @@ def perform_render
render_template_for(@__vc_variant).to_s + _output_postamble
end

# Subclass components that call `super` inside their template code will cause a
# double render if they accidentally emit the result:
#
# <%= super %> # double-renders
#
# <% super %> # does not double-render
#
# Calls `super`, returning nil to avoid rendering the result twice.
def render_parent
mtd = @__vc_variant ? "call_#{@__vc_variant}" : "call"
method(mtd).super_method.call
nil
end

# :nocov:
def render_template_for(variant = nil)
# Force compilation here so the compiler always redefines render_template_for.
Expand Down
1 change: 1 addition & 0 deletions test/sandbox/app/components/super_base_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="base-component"></div>
4 changes: 4 additions & 0 deletions test/sandbox/app/components/super_base_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

class SuperBaseComponent < ViewComponent::Base
end
3 changes: 3 additions & 0 deletions test/sandbox/app/components/super_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="derived-component">
<%= render_parent %>
</div>
4 changes: 4 additions & 0 deletions test/sandbox/app/components/super_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

class SuperComponent < SuperBaseComponent
end
9 changes: 9 additions & 0 deletions test/view_component/view_component_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1014,4 +1014,13 @@ def test_inherited_component_renders_when_lazy_loading
render_inline(InheritedWithOwnTemplateComponent.new)
assert_selector("div", text: "hello, my own template")
end

def test_inherited_component_calls_super
render_inline(SuperComponent.new)

assert_selector(".base-component", count: 1)
assert_selector(".derived-component", count: 1) do
assert_selector(".base-component", count: 1)
end
end
end

0 comments on commit 1ea088f

Please sign in to comment.