ViewComponent On Rails
Published: 2021-10-20 17:46:45

## Introducción.

Si hay algo que siempre me ha gustado de ruby/rails es su comunidad, siento que es una comunidad súper rica en nuevas propuestas, que sigue con buenas convenciones y que ademas siempre trata de tener el código ordenado. De tal manera que al momento de crear algo nos evitemos tantos comentarios en el código y este hable por si mismo.

## Que es ViewComponent?.
ViewComponent viene a ser un entorno de trabajo para la creación de componentes encapsulados de vistas que pueden ser reutilizables y testeables con mayor facilidad.
En este breve tutorial nos vamos a enfocar en crear ViewComponents básicos.

## La problemática (Barra de progreso)!
Supongamos que tenemos la necesidad de crear una barra de progreso para varias vistas en una aplicación. 
Por ejemplo en una todo list o en un finance tracker o algo parecido, el caso es que queremos que por lo menos este mas de una vez repetido este componente sobre nuestra aplicación.
Primero que nada imagínense la repetición de código HTML que vamos a tener que incorporar en nuestra aplicación, sinceramente esto no es practico y para nada estaríamos respetando el DRY.
```HTML
<div class="progress">
  <div class="progress-bar" role="progressbar" style="width: <%= @valor_de_tu_objeto %>" aria-valuenow="<%= @valor_de_tu_objeto %>" aria-valuemin="0" aria-valuemax="100"></div>
</div>
```
Lo cual nos desplegara lo siguiente en cada una de las vistas que deseemos.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ocfadk1qyawq36aleyc.png)
Para venir a salvarnos de este tipo de cosas y tener mejor organizado nuestro código aquí es en donde se presentan los ViewComponents.
![Yes](https://media.giphy.com/media/vvbGMpbhZMcHSsD50w/giphy.gif)

## Hands On
Para poder hacer uso de los ViewComponents es necesario instalar la siguiente gema.
```Ruby
gem "view_component", require: "view_component/engine"

# Posteriormente ejecutar bundle install
```
Una vez instalada la gema procederemos a crear el componente con el siguiente comando.
```Ruby
bin/rails g component ProgressBarComponent value
```
Este comando nos creara mas o menos la siguiente salida en terminal
```Ruby
invoke test_unit
create test/components/progress_bar_component_test.rb
create app/components/progress_bar_component.rb
create app/components/progress_bar_component.html.erb
```
Por lo tanto con esto podemos deducir que un ViewComponent esta compuesto por un archivo (progress_bar_component.rb) y una plantilla (progress_bar_component.html.erb).
Dado que cuando ejecutamos el generador de componentes pasamos un atributo (value) entonces nuestro component lucirá de la siguiente manera.
```Ruby
# app/components/progress_bar_component.rb

# frozen_string_literal: true

class ProgressBarComponent < ViewComponent::Base
    def initialize(value:)
      @value = value
    end
end
```
Ahora sera momento de agregar nuestro código HTML para la barra de progreso de la siguiente manera.
```HTML
# app/components/progress_bar_component.html.erb
<div class="progress mb-4">
  <div class="progress-bar bg-info" role="progressbar" style="width: <%= @value %>%;" aria-valuenow="<%= @value %>" aria-valuemin="0" aria-valuemax="100" ></div>
</div>
```

## Llamada desde una vista diferente
Supongamos que deseamos ahora llamar a este componente desde una vista index en donde tengamos una todo list con una cantidad de porcentaje completado de un modelo, para poder hacerlo deberíamos de hacerlo de la siguiente manera.

* Calculamos el porcentaje completado de todos.
```Ruby
# app/models/todo.rb
def percent_complete
  Todo.count == 0 ? 0 : (100 * completed_items.to_f / total_items).round(1)
end
# El método anterior se puede descomponer para hacerlo mas legible ya lo dejo a su criterio.
```
* Mandamos a llamar desde la vista que deseemos implementar la barra de progreso.
```HTML
# app/views/todos/index.html.erb
<%= render(ProgressBarComponent.new(value: @todo.percent_complete)) %>
```
De esta manera este componente es totalmente re-utilizable en cualquier otra vista de nuestra aplicación sin necesidad de escribir nuevamente el código HTML y solo mandando a llamar al componente por medio del método render.

## Fuentes y Recomendaciones.

* [View Components](https://viewcomponent.org/)
* Revisen con detenimiento las colecciones con ViewComponents son una chulada para reducir código.
* He estado probando los ViewComponents con alguna que otra cosilla de Stimulus Reflex (en algún momento hablare acerca de este tema) y les puedo comentar que trabajan muy bien en conjunto.