E-commerce "Depot"
Inicialmente "Depot" é um e-commerce baseado na web desenvolvido com Ruby on Rails 7 seguindo o tutorial do livro Agile Web Development with rails 7. Neste post descrevo o projeto desenvolvido, minha experiencia, desafios e algumas ferramentas utilizadas para desenvolver esse projeto.
Agile Web Development with rails 7
Agile Web Development with Rails 7 ensina, passo a passo, como criar um aplicativo completo com Ruby on Rails. O livro aborda o desenvolvimento de uma loja virtual, integrando JavaScript, envio de e-mails, tarefas assíncronas com Active Job e funcionalidades em tempo real com Action Cable. Além disso, apresenta também outros recursos e técnicas como testes e internacionalização. Com uma abordagem prática e progressiva, é ideal tanto para iniciantes quanto para desenvolvedores que desejam aprimorar suas habilidades no framework. Um ótimo guia para dominar Rails e seus recursos mais recentes.
Depot: Uma Loja Virtual Baseada na Web

O Depot, como mencionado na introdução, é uma aplicação de loja virtual desenvolvida como parte de um tutorial de aprendizado em Rails. O projeto desenvolvido seguindo o tutorial está disponível no repositório Learning-storage do meu perfil do GitHub. Ele foi inspirado no site The Pragmatic Bookshelf e serve como um excelente exemplo de como estruturar uma aplicação completa com diversas funcionalidades.
O Depot apresenta algumas funcionalidades principais de uma loja virtual como:
- Catálogo de produtos com exibição detalhada.
- Gestão de pedidos e carrinhos de compras.
- Integração com sistema de envio de emails.
- Lista de pedidos.
- Interface interativa para clientes.

O Depot foi construído para explorar conceitos fundamentais do framework Rails e ferramentas modernas. Este projeto é otimo para quem deseja aprender sobre desenvolvimento de aplicações web com Ruby on Rails e explorar funcionalidades práticas e modernas em um ambiente de aprendizado controlado, e futuramente será lançado a nova versão desse livro, porem abordando a versão 8 de Ruby on Rails.
Minha Experiência
Desenvolver essa loja virtual foi uma experiência gratificante. O livro me permitu mair aproximação com o framework Ruby on Rails, permitindo aprender conceitos fundamentais como arquitetura MVC, ORM e uso de concerns. Além disso, apresentou uma introdução prática à linguagem Ruby, abordando tópicos como tipos de dados, arrays, hashes e métodos. O destaque do livro está na sua abordagem didática: explicações claras e objetivas, seguidas por códigos e desafios práticos para consolidar os conhecimentos adquiridos.
Outro marco importante foi minha primeira experiência com o uso do Docker para fazer o deploy da aplicação. Até então, eu havia utilizado apenas plataformas de hospedagem como Heroku e Render. Durante o desenvolvimento, foi utilizado o banco de dados SQLite, enquanto o deploy foi realizado com PostgreSQL.
Entre as ferramentas destacadas, foi utilizado o Action Text para oferecer maior liberdade de personalização ao cliente, especialmente na descrição dos produtos. Além disso, tive minha primeira experiência com o Action Cable, implementando funcionalidades em tempo real, como a atualização dinâmica da loja sempre que um produto é adicionado, editado ou removido. Também explorei o Stimulus para tornar o formulário de compra mais dinâmico, ajustando os campos exibidos de acordo com o método de pagamento selecionado.
O uso do I18n (internacionalização) foi mais uma descoberta neste projeto. Essa funcionalidade permitiu adicionar suporte para inglês e espanhol, tornando a aplicação mais acessível. Configurei traduções para lidar com formatações específicas de datas, moedas e mensagens personalizadas em diversos contextos da aplicação. Essa prática melhorou a usabilidade e acessibilidade.
Os concerns foram outra ferramenta valiosa que aprendi a utilizar durante o projeto. Com eles, consegui extrair lógica compartilhada entre diferentes modelos e controladores, mantendo o código limpo e reutilizável. Essa abordagem trouxe maior organização para o código, especialmente ao trabalhar com funcionalidades comuns.
Também houve um aperfeiçoamento na aplicação da arquitetura MVC e do padrão ORM. É importante separar de forma mais clara as responsabilidades entre modelos, controladores e visões, mantendo cada parte focada em seu propósito específico. No contexto do ORM, explorei as capacidades do Active Record para lidar com consultas complexas, associações e validações, simplificando bastante a manipulação dos dados.
Por fim, a configuração de emails foi realizada com Action Mailer, combinado com Active Job, ferramenta que já havia utilizado anteriormente. Um exemplo é meu projeto de agendamento de tweets, "Scheduled Tweets", onde usei Active Job e Sidekiq para gerenciar filas de tarefas. É incrivel a versatilidade desse framework.
Desafios
Nesse topico vou apresentar dois desafios que fiz enquanto desenvolvia o projeto lendo o livro, um de nivel mais basico e outro mais avançado, dentro do livro existe varios outros desafios como: calcular quantas vezes foi visitado uma parte do site, escrever testes especificos e adicionar validações, então não seria viavel adicionar todos os desafios. Também esta presente neste tópico, uma breve descrição de algumas ferramentas, conceitos e funcionamento do algoritmo desenvolvido.
-
Desafio 1: Apos criar tabelas no banco de dados usando migration, examinar as tabelas diretamente executando bin/rails dbconsole.
Consultando informações do banco de dados atraves do cmd executando "rails dbconsole". esse comando permite comunicar com banco de dados da aplicação diretamente do cmd.
n-colas@n-colas-VirtualBox:~/Development/Learning-storage$ rails dbconsole SQLite version 3.45.1 2024-01-30 16:01:20 Enter ".help" for usage hints. sqlite> .mode line sqlite> SELECT id, title, price FROM products; id = 1 title = Docker for Rails Developers price = 19.95 id = 2 title = Design and Build Great Web APIs price = 24.95 id = 3 title = Modern CSS with Tailwind price = 18.95 sqlite>
Ao executar o comando SQL SELECT id, title, price FROM products; no terminal, é possível obter os dados de três atributos específicos da tabela de produtos cadastrados na loja: o identificador (id), o título (title) e o preço (price). A tabela de produtos contém outros parâmetros, como descrição (description), URL da imagem (image_url) e localidade (locale), mas a consulta SQL foi configurada para retornar apenas os três primeiros parâmetros. Desse modo, é possivel perceber que o banco de dados funciona é permite fazer consultas e manipulação de dados.
-
Desafio 2: Implementar decremento de produtos do carrinho e atualizar o carrinho usando Hotwire.
Hotwire: Um conjunto de tecnologias desenvolvido para criar aplicações web interativas com alta performance, minimizando a dependência de JavaScript pesado no lado do cliente. Ele é composto por três principais ferramentas:
- Turbo: Substitui a necessidade de JavaScript personalizado para atualizações parciais de páginas, utilizando técnicas como Turbo Frames e Turbo Streams para entregar interatividade diretamente do servidor.
- Stimulus: Um framework leve para adicionar comportamento dinâmico a elementos HTML, tornando o código mais organizado e mantendo a lógica do lado do cliente simples e declarativa.
- Strada: Um recurso que conecta o front-end web a aplicativos nativos, permitindo interações híbridas entre os dois ambientes.
Partials Partiais em Ruby on Rails são arquivos de visualização reutilizáveis que ajudam a evitar a repetição de código. Elas permitem que você extraia trechos de HTML e Ruby que se repetem em diferentes partes do aplicativo, tornando o código mais limpo e modular. Partiais são carregadas com o método render, que pode ser usado para inserir uma parcial em outra visualização ou layout. O nome do arquivo de uma parcial geralmente começa com um sublinhado (_), como _form.html.erb, para indicar que é uma parte de uma visualização maior.
Funcionamento da funcionalidade de decrementos
O método destroy no controlador line_items_controller tem como função principal reduzir a quantidade de itens no carrinho ou removê-los completamente quando a quantidade atinge 1. Essa lógica garante que o estado do carrinho seja sempre atualizado corretamente, tanto para decrementos quanto para exclusões completas. O método também utiliza Turbo Stream para atualização dinâmica, além de suportar redirecionamentos em HTML e respostas em JSON para maior flexibilidade.
# controllers/line_items_controller.rb def destroy if @line_item.quantity > 1 @line_item.update(quantity: @line_item.quantity - 1) else @line_item.destroy end respond_to do |format| format.turbo_stream format.html { redirect_to store_index_url } format.json { head :no_content } end end
O arquivo destroy.turbo_stream.erb é utilizado para atualizar a interface do usuário de forma dinâmica. Quando um item é completamente removido do carrinho, a partial `_cart` é renderizada novamente, mostrando a lista atualizada de itens no carrinho. Caso apenas a quantidade seja reduzida, o carrinho é atualizado com a nova quantidade do item. Em ambos os casos, mensagens informativas são exibidas para o usuário, detalhando a ação realizada.
# views/line_items/destroy.turbo_stream.erb <% if @line_item.destroyed? %> <%= turbo_stream.replace 'cart', partial: 'layouts/cart', locals: { cart: @cart } %> <%= turbo_stream.replace 'notice', partial: 'store/notice', locals: { notice: "The '#{@line_item.product.title}' was successfully destroyed." } %> <% else %> <%= turbo_stream.update 'cart', partial: 'layouts/cart', locals: { cart: @cart } %> <%= turbo_stream.replace 'notice', partial: 'store/notice', locals: { notice: "Only one '#{@line_item.product.title}' was successfully destroyed." } %> <% end %>
O arquivo _cart.html.erb, localizado em views/layouts, define a exibição do carrinho na interface principal. Ele verifica se o carrinho contém itens para determinar se o conteúdo deve ser renderizado ou se um contêiner vazio deve ser exibido. Essa abordagem garante que a interface permaneça consistente, independentemente do estado atual do carrinho.
# views/layouts/_cart.html.erb <% if cart and not cart.line_items.empty? %> <div id="cart" class="bg-white rounded p-2"> <%= render @cart %> </div> <% else %> <div id="cart"></div> <% end %>
O arquivo _cart.html.erb, localizado em views/carts, define a estrutura detalhada do carrinho. Ele inclui a lista de itens adicionados, o total do carrinho e botões para esvaziar o carrinho ou finalizar a compra. Esses elementos permitem uma interação completa e intuitiva para o usuário.
# views/carts/_cart.html.erb <div id="<%= dom_id cart %>"> <h2 class="font-bold text-lg mb-3"> <%= t('.title') %> </h2> <table class="table-auto"> <%= render cart.line_items %> <tfoot> <tr> <th class="text-right pr-2 pt-2" colspan="3">Total:</th> <td class="text-right pt-2 font-bold border-t-2 border-black"> <%= number_to_currency(cart.total_price) %> </td> </tr> </tfoot> </table> <div class="flex mt-1"> <%= button_to t('.empty'), cart, method: :delete, class: 'ml-4 rounded-lg py-1 px-2 text-white bg-green-600' %> <% if @order.nil? %> <%= button_to t('.checkout'), new_order_path(locale: I18n.locale), method: :get, class: 'ml-4 rounded-lg py-1 px-2 text-black bg-green-200' %> <% else %> <% end %> </div> </div>
O arquivo _line_item.html.erb define como cada item individual no carrinho é exibido. Ele mostra detalhes como quantidade, título do produto, preço total e um botão para remover o item. Esse layout dinâmico garante que os usuários possam interagir facilmente com os produtos do carrinho.
# views/line_items/_line_item.html.erb <div id="<%= dom_id line_item %>"> <% if line_item == @current_item %> <tr class="line-item-highlight"> <% else %> <tr> <% end %> <td class="text-right"><%= line_item.quantity %>×</td> <td class="pr-2"> <%= line_item.product.title %> </td> <td class="text-right font-bold"> <%= number_to_currency(line_item.total_price) %> </td> <td> <%= button_to 'destroy', line_item, method: :delete, class: 'rounded-lg py-1 px-2 text-white bg-green-600' %> </td> </tr> </div>
Resultado
Funcionamento geral da funcionalidade
O método destroy no controlador line_items_controller é responsável por manipular a remoção de um item do carrinho ou por reduzir a quantidade de um produto, respondendo com Turbo Stream, HTML ou JSON. Quando um item é removido ou sua quantidade reduzida, as views são atualizadas dinamicamente. A view destroy.turbo_stream.erb atualiza a interface do carrinho e exibe uma mensagem, enquanto a partial _cart.html.erb re-renderiza o conteúdo do carrinho, incluindo os itens atualizados. A partial _line_item.html.erb exibe cada item individual no carrinho, e ao ser acionada, interage com o controlador para refletir as mudanças na UI. O Turbo Stream permite que essas atualizações aconteçam sem recarregar a página. O uso do Turbo Stream permite atualizar a interface de forma dinâmica, sem a necessidade de recarregar a página inteira. Isso significa que, após a remoção ou decremento de um item, apenas a parte da página que precisa ser alterada (o carrinho, no caso) será atualizada. Além disso, é exibida uma mensagem informando ao usuário o que ocorreu: se o item foi removido completamente ou se a quantidade foi diminuída.
Conclusão
Este foi, sem dúvidas, o projeto mais longo e desafiador que já desenvolvi, mas também o mais enriquecedor em termos de aprendizado e crescimento profissional. Ao longo do processo, pude consolidar conceitos fundamentais do Ruby on Rails, explorar ferramentas modernas e aprimorar minhas habilidades em desenvolvimento web. O fato de seguir uma versão totalmente em inglês também proporcionou um aprimoramento no meu domínio do idioma, agregando mais valor à experiência.
O projeto me apresentou a cenários reais, como o uso de bancos de dados distintos para desenvolvimento e produção, integração de funcionalidades em tempo real com Action Cable e dinamismo nos formulários com Stimulus. Além disso, foi uma oportunidade para experimentar o Docker no deploy, o que expande minha visão sobre a gestão de ambientes em produção. Cada desafio enfrentado e superado ao longo dessa jornada foi extremamente divertido, fornecendo uma base sólida e prática para continuar evoluindo como desenvolvedor.