Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/bundler/better_html-2.0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
joelhawksley authored Jul 3, 2023
2 parents 8a17df6 + 920b860 commit 31e806b
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 80 deletions.
48 changes: 19 additions & 29 deletions docs/guide/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ Since 2.1.0
Like [Rails partials](https://guides.rubyonrails.org/layouts_and_rendering.html#rendering-collections), it's possible to render a collection with ViewComponents, using `with_collection`:

```erb
<%# app/view/products/index.html.erb %>
<%= render(ProductComponent.with_collection(@products)) %>
```

```ruby
# app/components/product_component.rb
class ProductComponent < ViewComponent::Base
def initialize(product:)
@product = product
Expand All @@ -32,7 +30,6 @@ end
Use `with_collection_parameter` to change the name of the collection parameter:

```ruby
# app/components/product_component.rb
class ProductComponent < ViewComponent::Base
with_collection_parameter :item

Expand All @@ -47,30 +44,27 @@ end
Additional arguments besides the collection are passed to each component instance:

```erb
<%# app/view/products/index.html.erb %>
<%= render(ProductComponent.with_collection(@products, notice: "hi")) %>
```

```ruby
# app/components/product_component.rb
class ProductComponent < ViewComponent::Base
with_collection_parameter :item

erb_template <<-ERB
<li>
<h2><%= @item.name %></h2>
<span><%= @notice %></span>
</li>
ERB

def initialize(item:, notice:)
@item = item
@notice = notice
end
end
```

```erb
<%# app/components/product_component.html.erb %>
<li>
<h2><%= @item.name %></h2>
<span><%= @notice %></span>
</li>
```

## Collection counter

Since 2.5.0
Expand All @@ -79,22 +73,20 @@ Since 2.5.0
ViewComponent defines a counter variable matching the parameter name above, followed by `_counter`. To access the variable, add it to `initialize` as an argument:

```ruby
# app/components/product_component.rb
class ProductComponent < ViewComponent::Base
erb_template <<-ERB
<li>
<%= @counter %> <%= @product.name %>
</li>
ERB

def initialize(product:, product_counter:)
@product = product
@counter = product_counter
end
end
```

```erb
<%# app/components/product_component.html.erb %>
<li>
<%= @counter %> <%= @product.name %>
</li>
```

## Collection iteration context

Since 2.33.0
Expand All @@ -105,18 +97,16 @@ ViewComponent defines an iteration variable matching the parameter name above, f
To access the variable, add it to `initialize` as an argument:

```ruby
# app/components/product_component.rb
class ProductComponent < ViewComponent::Base
erb_template <<-ERB
<li class="<%= "featured" if @iteration.first? %>">
<%= @product.name %>
</li>
ERB

def initialize(product:, product_iteration:)
@product = product
@iteration = product_iteration
end
end
```

```erb
<%# app/components/product_component.html.erb %>
<li class="<%= "featured" if @iteration.first? %>">
<%= @product.name %>
</li>
```
14 changes: 6 additions & 8 deletions docs/guide/conditional_rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ or the view that renders the component:
Using the `#render?` hook simplifies the view:

```ruby
# app/components/confirm_email_component.rb
class ConfirmEmailComponent < ViewComponent::Base
erb_template <<-ERB
<div class="banner">
Please confirm your email address.
</div>
ERB

def initialize(user:)
@user = user
end
Expand All @@ -42,13 +47,6 @@ class ConfirmEmailComponent < ViewComponent::Base
end
```

```erb
<%# app/components/confirm_email_component.html.erb %>
<div class="banner">
Please confirm your email address.
</div>
```

```erb
<%= render(ConfirmEmailComponent.new(user: current_user)) %>
```
Expand Down
16 changes: 5 additions & 11 deletions docs/guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,25 @@ Available options to customize the generator are documented on the [Generators](

## Implementation

A ViewComponent is a Ruby file and corresponding template file with the same base name:
A ViewComponent is a Ruby class that inherits from `ViewComponent::Base`:

```ruby
# app/components/example_component.rb
class ExampleComponent < ViewComponent::Base
erb_template <<-ERB
<span title="<%= @title %>"><%= content %></span>
ERB

def initialize(title:)
@title = title
end
end
```

```erb
<%# app/components/example_component.html.erb %>
<span title="<%= @title %>"><%= content %></span>
```

Content passed to a ViewComponent as a block is captured and assigned to the `content` accessor.

Rendered in a view as:

```erb
<%# app/views/home/index.html.erb %>
<%= render(ExampleComponent.new(title: "my title")) do %>
Hello, World!
<% end %>
Expand All @@ -82,7 +79,6 @@ Since 2.31.0
String content can also be passed to a ViewComponent by calling `#with_content`:

```erb
<%# app/views/home/index.html.erb %>
<%= render(ExampleComponent.new(title: "my title").with_content("Hello, World!")) %>
```

Expand All @@ -91,7 +87,6 @@ String content can also be passed to a ViewComponent by calling `#with_content`:
It's also possible to render ViewComponents in controllers:

```ruby
# app/controllers/home_controller.rb
def show
render(ExampleComponent.new(title: "My Title"))
end
Expand All @@ -102,7 +97,6 @@ _Note: Content can't be passed to a component via a block in controllers. Instea
When using turbo frames with [turbo-rails](https://github.com/hotwired/turbo-rails), set `content_type` as `text/html`:

```ruby
# app/controllers/home_controller.rb
def create
render(ExampleComponent.new, content_type: "text/html")
end
Expand Down
42 changes: 20 additions & 22 deletions docs/guide/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,28 @@ parent: How-to guide

ViewComponents wrap a template (or several, if using [variants](https://guides.rubyonrails.org/layouts_and_rendering.html#the-variants-option)), defined in one of several ways:

## Inline

Since 3.0.0
{: .label }

To define a template inside a component, call the `.TEMPLATE_HANDLER_template` macro:

```ruby
class InlineErbComponent < ViewComponent::Base
erb_template <<~ERB
<h1>Hello, <%= @name %>!</h1>
ERB

def initialize(name)
@name = name
end
end
```

## Sibling file

The simplest option is to place the view next to the Ruby component:
Place template file next to the component:

```console
app/components
Expand Down Expand Up @@ -82,27 +101,6 @@ end

_**Note**: `call_*` methods must be public._

## Inline

Since 3.0.0
{: .label }

To define a template inside a component, call the `.TEMPLATE_HANDLER_template` macro:

```ruby
class InlineErbComponent < ViewComponent::Base
attr_reader :name

erb_template <<~ERB
<h1>Hello, <%= name %>!</h1>
ERB

def initialize(name)
@name = name
end
end
```

## Inherited

Since 2.19.0
Expand Down
15 changes: 6 additions & 9 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,23 @@ A framework for creating reusable, testable & encapsulated view components, buil

## What's a ViewComponent?

Think of ViewComponents as an evolution of the presenter pattern, inspired by [React](https://reactjs.org/docs/react-component.html). A ViewComponent is a Ruby object and template:
Think of ViewComponents as an evolution of the presenter pattern, inspired by [React](https://reactjs.org/docs/react-component.html). A ViewComponent is a Ruby object:

```ruby
# app/components/message_component.rb
class MessageComponent < ViewComponent::Base
erb_template <<-ERB
<h1>Hello, <%= @name %>!</h1>
ERB

def initialize(name:)
@name = name
end
end
```

```erb
<%# app/components/message_component.html.erb %>
<h1>Hello, <%= @name %>!</h1>
```

Which is instantiated and passed to Rails' `#render`:

```erb
<%# app/views/demo/index.html.erb %>
<%= render(MessageComponent.new(name: "World")) %>
```

Expand Down Expand Up @@ -85,7 +82,7 @@ Based on several [benchmarks](https://github.com/viewcomponent/view_component/bl

The primary optimization is pre-compiling all ViewComponent templates at application boot, instead of at runtime like traditional Rails views.

For example, the `MessageComponent` template is compiled onto the Ruby object like so:
For example, the `MessageComponent` template is compiled onto the Ruby object:

```ruby
# app/components/message_component.rb
Expand Down
2 changes: 1 addition & 1 deletion test/sandbox/test/integration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def test_rendering_component_with_a_partial
get "/partial"
assert_response :success

assert_select("div", "hello,partial world!", count: 2)
assert_select("div", {text: "hello,partial world!", count: 4})
end

def test_rendering_component_without_variant
Expand Down

0 comments on commit 31e806b

Please sign in to comment.