Visitar URL original
Document rendering `:renderable` and `#render_in` by seanpdoyle · Pull Request #50622 · rails/rails · GitHub
Skip to content

Document rendering :renderable and #render_in - #50622

Merged
rafaelfranca merged 1 commit into
rails:mainfrom
seanpdoyle:document-render-in-examples
Jan 8, 2024
Merged

rafaelfranca merged 1 commit into
rails:mainfrom
seanpdoyle:document-render-in-examples

Conversation

@seanpdoyle

Copy link
Copy Markdown
Contributor

Motivation / Background

Provide examples for rendering objects that respond to render_in. Also highlight that the object can also define a #format method to control how the rendered String should be treated.

Detail

Add test coverage for both Action View's and Action Pack's support for render with :renderable options.

Provide examples for rendering objects that respond to `render_in`. Also
highlight that the object can also define a `#format` method to control
how the rendered String should be treated.

Add test coverage for both Action View's and Action Pack's support for
`render` with `:renderable` options.
@seanpdoyle
seanpdoyle force-pushed the document-render-in-examples branch from cadcb88 to 4117583 Compare January 6, 2024 22:57
@rafaelfranca
rafaelfranca merged commit 84f773f into rails:main Jan 8, 2024
@seanpdoyle
seanpdoyle deleted the document-render-in-examples branch January 8, 2024 23:19

def format
@renderable.format
@renderable.try(:format)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was failing?

Comment on lines +378 to +381
def test_render_renderable_render_in
assert_equal "Hello, World!", @view.render(TestRenderable.new)
assert_equal "Hello, World!", @view.render(renderable: TestRenderable.new)
end

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@p8 yes, this addition combined with this change fails the suite:

--- a/actionview/lib/action_view/template/renderable.rb
+++ b/actionview/lib/action_view/template/renderable.rb
@@ -17,7 +17,7 @@ def render(context, *args)
       end
 
       def format
-        @renderable.try(:format)
+        @renderable.format
       end
     end
   end
Running 3020 tests in parallel using 12 processes
Run options: --seed 64876

# Running:

....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................E

Error:
CachedCollectionViewRenderTest#test_render_renderable_render_in:
NoMethodError: private method `format' called for #<TestRenderable:0x000000010add4270>
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/template/renderable.rb:20:in `format'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/template_renderer.rb:9:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:58:in `render_template_to_object'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:31:in `render_to_object'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:24:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/helpers/rendering_helper.rb:37:in `block in render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/base.rb:291:in `in_rendering_context'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/helpers/rendering_helper.rb:33:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/test/template/render_test.rb:380:in `test_render_renderable_render_in'

bin/test test/template/render_test.rb:378

.......................................................................................................................................................E

Error:
FrozenStringLiteralEnabledViewRenderTest#test_render_renderable_render_in:
NoMethodError: private method `format' called for #<TestRenderable:0x0000000105277670>
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/template/renderable.rb:20:in `format'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/template_renderer.rb:9:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:58:in `render_template_to_object'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:31:in `render_to_object'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:24:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/helpers/rendering_helper.rb:37:in `block in render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/base.rb:291:in `in_rendering_context'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/helpers/rendering_helper.rb:33:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/test/template/render_test.rb:380:in `test_render_renderable_render_in'

bin/test test/template/render_test.rb:378

.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................E

Error:
LazyViewRenderTest#test_render_renderable_render_in:
NoMethodError: private method `format' called for #<TestRenderable:0x000000010a7d10d0>
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/template/renderable.rb:20:in `format'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/template_renderer.rb:9:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:58:in `render_template_to_object'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:31:in `render_to_object'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:24:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/helpers/rendering_helper.rb:37:in `block in render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/base.rb:291:in `in_rendering_context'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/helpers/rendering_helper.rb:33:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/test/template/render_test.rb:380:in `test_render_renderable_render_in'

bin/test test/template/render_test.rb:378

...............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................E

Error:
CachedViewRenderTest#test_render_renderable_render_in:
NoMethodError: private method `format' called for #<TestRenderable:0x000000010a4b01f8>
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/template/renderable.rb:20:in `format'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/template_renderer.rb:9:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:58:in `render_template_to_object'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:31:in `render_to_object'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/renderer/renderer.rb:24:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/helpers/rendering_helper.rb:37:in `block in render'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/base.rb:291:in `in_rendering_context'
    /Users/seanpdoyle/Work/rails/rails/actionview/lib/action_view/helpers/rendering_helper.rb:33:in `render'
    /Users/seanpdoyle/Work/rails/rails/actionview/test/template/render_test.rb:380:in `test_render_renderable_render_in'

bin/test test/template/render_test.rb:378

.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

Finished in 1.125893s, 2682.3153 runs/s, 5853.1317 assertions/s.
3020 runs, 6590 assertions, 0 failures, 4 errors, 0 skips

Given the fact that this PR documented an implicit public API, I opted to make the API conditional rather than make this change instead:

diff --git a/actionview/lib/action_view/template/renderable.rb b/actionview/lib/action_view/template/renderable.rb
index c37bd1cb5e..52af19f947 100644
--- a/actionview/lib/action_view/template/renderable.rb
+++ b/actionview/lib/action_view/template/renderable.rb
@@ -17,7 +17,7 @@ def render(context, *args)
       end
 
       def format
-        @renderable.try(:format)
+        @renderable.format
       end
     end
   end
diff --git a/actionview/test/lib/test_renderable.rb b/actionview/test/lib/test_renderable.rb
index c2b7411e14..46e2f8983c 100644
--- a/actionview/test/lib/test_renderable.rb
+++ b/actionview/test/lib/test_renderable.rb
@@ -4,4 +4,8 @@ class TestRenderable
   def render_in(_view_context)
     "Hello, World!"
   end
+
+  def format
+    :html
+  end
 end

Do we think that it's worthwhile to remove the call to #try as part of #50623?

@p8 p8 Jan 9, 2024 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, interesting. I wasn't aware try allows calling private methods.
If format is expected in the Renderable API shouldn't if be public always?

Edit: Sorry, try returns nil for private methods. I think that might be unexpected in this case.

@seanpdoyle seanpdoyle Jan 9, 2024 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@p8 the call to .try(:format) is returning nil because it's treating @renderable as if it doesn't respond to #format.

If the object doesn't define its own #format method, then the private method references Kernel#format:

CachedViewRenderTest#test_render_renderable_render_in:
RuntimeError: #format defined at: #<Method: TestRenderable(Kernel)#format(*)>

That failure is raised by this change:

diff --git a/actionview/lib/action_view/template/renderable.rb b/actionview/lib/action_view/template/renderable.rb
index c37bd1cb5e..bec7ea5fba 100644
--- a/actionview/lib/action_view/template/renderable.rb
+++ b/actionview/lib/action_view/template/renderable.rb
@@ -17,7 +17,8 @@ def render(context, *args)
       end
 
       def format
-        @renderable.try(:format)
+        fail "#format defined at: #{@renderable.method(:format)}"
       end
     end
   end

If format is expected in the Renderable API shouldn't if be public always?

Is that a breaking change? Should this .try(:format) be accompanied by a deprecation warning that we can remove later?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The private format in question here is Kernel#format. This code is correct, there is no need for deprecations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants