Skip to content

Add default #render_in implementation to ActiveModel::Conversion #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: action-view-render-in-options
Choose a base branch
from

Conversation

seanpdoyle
Copy link
Owner

Follow-up to #46202

Without overriding the new #render_in method, previous behavior will be preserved: render the view partial determined by calling #to_partial_path, then pass object: self.

With the following view partial:

<%# app/views/people/_person.html.erb %>
<% local_assigns.with_defaults(shout: false) => { shout: } %>

<%= shout ? person.name.upcase : person.name %>

Callers can render an instance of Person as a positional argument or a :renderable option:

person = Person.new(name: "Ralph")

render person                                       # => "Ralph"
render person, shout: true                          # => "RALPH"
render renderable: person                           # => "Ralph"
render renderable: person, locals: { shout: true }  # => "RALPH"

This preserves backward compatibility. At the same time, the #render_in method provides applications with an more flexibility, and an opportunity to manage how to transform models into Strings. For example, users of ViewComponent can map a model directly to a ViewComponent::Base instance.

Summary

Other Information

@seanpdoyle seanpdoyle force-pushed the active-model-conversion-render-in branch from 9e9f75f to bbff5f5 Compare January 6, 2024 22:56
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch 6 times, most recently from 8a1754a to cb1b21b Compare January 9, 2024 01:07
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
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from cb1b21b to b554fd3 Compare January 9, 2024 03:31
@seanpdoyle seanpdoyle force-pushed the active-model-conversion-render-in branch from bbff5f5 to af82a27 Compare January 9, 2024 04:29
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 159b549 to 1ba6b9f Compare January 9, 2024 04:37
Follow-up to [rails#46202][]

Without overriding the new `#render_in` method, previous behavior will
be preserved: render the view partial determined by calling
`#to_partial_path`, then pass `object: self`.

With the following view partial:

```erb
<%# app/views/people/_person.html.erb %>
<% local_assigns.with_defaults(shout: false) => { shout: } %>

<%= shout ? person.name.upcase : person.name %>
```

Callers can render an instance of `Person` as a positional argument or a
`:renderable` option:

```ruby
person = Person.new(name: "Ralph")

render person                                       # => "Ralph"
render person, shout: true                          # => "RALPH"
render renderable: person                           # => "Ralph"
render renderable: person, locals: { shout: true }  # => "RALPH"
```

This preserves backward compatibility. At the same time, the
`#render_in` method provides applications with an more flexibility, and
an opportunity to manage how to transform models into Strings. For
example, users of ViewComponent can map a model directly to a
`ViewComponent::Base` instance.

[rails#46202]: rails#46202 (comment)
@seanpdoyle seanpdoyle force-pushed the active-model-conversion-render-in branch from af82a27 to 6123414 Compare January 9, 2024 04:37
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch 11 times, most recently from 8f14f10 to 39af464 Compare January 12, 2024 16:57
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 39af464 to 1d390d1 Compare January 30, 2024 03:15
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch 2 times, most recently from 4161fe4 to 94926db Compare February 22, 2024 20:09
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 94926db to 1c1918c Compare March 2, 2024 15:09
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch 3 times, most recently from 465e84a to 98f1705 Compare March 8, 2024 13:29
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 98f1705 to 56a1e49 Compare March 24, 2024 23:48
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 56a1e49 to 97a7a97 Compare April 5, 2024 12:44
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch 3 times, most recently from 77867f2 to cd57c45 Compare April 24, 2024 13:22
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch 2 times, most recently from 3b2546e to 7f2d39e Compare May 16, 2024 17:17
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 7f2d39e to dbed3b1 Compare July 13, 2024 11:52
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from dbed3b1 to 4c26fcd Compare August 2, 2024 21:23
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch 2 times, most recently from a92e0e8 to 33d6dad Compare October 4, 2024 12:22
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 33d6dad to 1ea1ac5 Compare December 18, 2024 04:24
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 1ea1ac5 to 50c601b Compare January 17, 2025 18:20
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch 2 times, most recently from fdc3103 to 7614159 Compare July 16, 2025 18:11
@seanpdoyle seanpdoyle force-pushed the action-view-render-in-options branch from 7614159 to 15f9f6a Compare July 31, 2025 02:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant