Skip to content

Commit

Permalink
Merge pull request rails#36388 from joelhawksley/actionview-component
Browse files Browse the repository at this point in the history
Introduce ActionView::Component
  • Loading branch information
tenderlove authored Jun 13, 2019
2 parents 5a8714e + c221b5b commit 3683a82
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 1 deletion.
4 changes: 4 additions & 0 deletions actionview/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
* `RenderingHelper` supports rendering objects that `respond_to?` `:render_in`

*Joel Hawksley*, *Natasha Umer*, *Aaron Patterson*, *Shawn Allen*, *Emily Plummer*, *Diana Mounter*, *John Hawthorn*, *Nathan Herald*, *Zaid Zawaideh*, *Zach Ahn*

* Fix `select_tag` so that it doesn't change `options` when `include_blank` is present.

*Younes SERRAJ*
Expand Down
6 changes: 5 additions & 1 deletion actionview/lib/action_view/helpers/rendering_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ def render(options = {}, locals = {}, &block)
end
end
else
view_renderer.render_partial(self, partial: options, locals: locals, &block)
if options.respond_to?(:render_in)
options.render_in(self, &block)
else
view_renderer.render_partial(self, partial: options, locals: locals, &block)
end
end
end

Expand Down
46 changes: 46 additions & 0 deletions actionview/test/lib/test_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

class TestComponent < ActionView::Base
include ActiveModel::Validations

validates :content, :title, presence: true
delegate :render, to: :view_context

def initialize(title:)
@title = title
end

# Entrypoint for rendering. Called by ActionView::RenderingHelper#render.
#
# Returns ActionView::OutputBuffer.
def render_in(view_context, &block)
self.class.compile
@view_context = view_context
@content = view_context.capture(&block) if block_given?
validate!
rendered_template
end

def self.template
<<~'erb'
<span title="<%= title %>"><%= content %> (<%= render(plain: "Inline render") %>)</span>
erb
end

def self.compile
@compiled ||= nil
return if @compiled

class_eval(
"def rendered_template; @output_buffer = ActionView::OutputBuffer.new; " +
ActionView::Template::Handlers::ERB.erb_implementation.new(template, trim: true).src +
"; end"
)

@compiled = true
end

private

attr_reader :content, :title, :view_context
end
17 changes: 17 additions & 0 deletions actionview/test/template/render_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

require "abstract_unit"
require "controller/fake_models"
require "test_component"
require "active_model/validations"

class TestController < ActionController::Base
end
Expand Down Expand Up @@ -670,6 +672,21 @@ def test_render_with_passing_couple_extensions_to_one_register_template_handler_
def test_render_throws_exception_when_no_extensions_passed_to_register_template_handler_function_call
assert_raises(ArgumentError) { ActionView::Template.register_template_handler CustomHandler }
end

def test_render_component
assert_equal(
%(<span title="my title">Hello, World! (Inline render)</span>),
@view.render(TestComponent.new(title: "my title")) { "Hello, World!" }.strip
)
end

def test_render_component_with_validation_error
error = assert_raises(ActiveModel::ValidationError) do
@view.render(TestComponent.new(title: "my title")).strip
end

assert_match "Content can't be blank", error.message
end
end

class CachedViewRenderTest < ActiveSupport::TestCase
Expand Down

0 comments on commit 3683a82

Please sign in to comment.