Allow controller#render to pass blocks to renderables#45432
Allow controller#render to pass blocks to renderables#45432BlakeWilliams wants to merge 1 commit intorails:mainfrom
Conversation
There was a problem hiding this comment.
It seems like &block is never called in _normalize_args 🤷
https://github.com/rails/rails/blob/8e90517d41b711859f37ce55910579a8675b1c0c/actionpack/lib/abstract_controller/rendering.rb#L75-L88
Should it be passed as a regular argument instead and stored in options there?
There was a problem hiding this comment.
I think you're right, I noticed the same thing when writing this PR.
I avoided modifying it since it was existing code and I wanted to keep my changes relatively scoped, but happy to update it if folks feel it should be (I think we could not pass it to _normalize_args at all).
There was a problem hiding this comment.
I'm not sure...
Interestingly it does get used here, and added to the options:
rails/actionpack/lib/action_controller/metal/rendering.rb
Lines 87 to 91 in 436207a
Not sure where the :update option name comes from and where it's used. 🤔
Maybe you could use that as well for this PR?
Currently when controllers render Renderables (objects that respond to `#render_in`) blocks aren't passed to the renderable object. This differs from the `render` method in the view which does allow blocks to be passed. This updates the rendering code to pass a block throughout the call chain until it can be added to options, which are then used in the rendering logic to pass the block to the `Renderable` template class so that it can be used when `render` is called. This change allows controllers to pass blocks to renderables, matching the behavior of the view `render` method. It does so by passing the block though the call chain until it can be stored in the `options` hash. From there we pass the block to `ActionView::Template::Renderable.new` and the block is properly passed to the `render_in` method when `ActionView::Template::Renderable#render` is called. * Updates controller code to pass the block from `#render` until arguments are normalized. * Stores `block` in the `options` hash that is passed throughout the rendering call stack. * Updates `ActionView::Template::Renderable` to accept a block, which is then passed to the renderables `render_in` method. * Adds a test validating that blocks can be passed from controller renderers.
8e90517 to
17c0cc9
Compare
|
Looks like there is a syntax error causing the build to fail: Could you take a look? |
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render html: block.call else view_context.render inline: <<~ERB.strip, **options <%= Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render html: block.call else view_context.render inline: <<~ERB.strip, **options <%= Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render html: block.call else view_context.render inline: <<~ERB.strip, **options <%= Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render html: block.call else view_context.render inline: <<~ERB.strip, **options <%= Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render html: block.call else view_context.render inline: <<~ERB.strip, **options <%= Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **options, &block) if block view_context.render plain: block.call else case Array(options[:formats]).first when :json view_context.render json: { greeting: "Hello, World!" } else view_context.render **options, inline: "<%= Hello, <%= name %>!" end end end def format :html end end render(Greeting.new) # => "Hello, World!" render(Greeting.new, name: "Local") # => "Hello, Local!" render(Greeting.new) { "Hello, Block!" } # => "Hello, Block!" render(renderable: Greeting.new, formats: :json) # => "{\"greeting\":\"Hello, World!\"}" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **) if block_given? view_context.render(html: yield) else view_context.render(inline: <<~ERB.strip, **) Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **) if block_given? view_context.render(html: yield) else view_context.render(inline: <<~ERB.strip, **) Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **) if block_given? view_context.render(html: yield) else view_context.render(inline: <<~ERB.strip, **) Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **) if block_given? view_context.render(html: yield) else view_context.render(inline: <<~ERB.strip, **) Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **) if block_given? view_context.render(html: yield) else view_context.render(inline: <<~ERB.strip, **) Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **) if block_given? view_context.render(html: yield) else view_context.render(inline: <<~ERB.strip, **) Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **) if block_given? view_context.render(html: yield) else view_context.render(inline: <<~ERB.strip, **) Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Closes [rails#45432][] Support for objects that respond to `#render_in` was introduced in [rails#36388][] and [rails#37919][]. Those implementations assume that the instance will all the context it needs to render itself. That assumption doesn't account for call-site arguments like `locals: { ... }` or a block. This commit expands support for rendering with a `:renderable` option to incorporate locals and blocks. For example: ```ruby class Greeting def render_in(view_context, **) if block_given? view_context.render(html: yield) else view_context.render(inline: <<~ERB.strip, **) Hello, <%= name %> ERB end end end render(Greeting.new) # => "Hello, World" render(Greeting.new, name: "Local") # => "Hello, Local" render(Greeting.new) { "Hello, Block" } # => "Hello, Block" ``` Since existing tools depend on the `#render_in(view_context)` signature without options, this commit deprecates that signature in favor of one that accepts options and a block. [rails#45432]: rails#45432 [rails#36388]: rails#36388 [rails#37919]: rails#37919
Summary
Currently when controllers render Renderables (objects that respond to
#render_in) blocks aren't passed to the renderable object. Thisdiffers from the
rendermethod in the view which does allow blocks tobe passed.
e.g.
In controllers, the block in the following example will be silently ignored without
this patch:
This change allows controllers to pass blocks to renderables, matching
the behavior of the view
rendermethod. It does so by passing theblock through the call chain until it can be stored in the
optionshash. From there we pass the block to
ActionView::Template::Renderable.newand the block is properly passedto the
render_inmethod whenActionView::Template::Renderable#renderis called.
#renderuntilarguments are normalized.
blockin theoptionshash that is passed throughout therendering call stack.
ActionView::Template::Renderableto accept a block, which isthen passed to the renderables
render_inmethod.renderers.