<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alef Ojeda de Oliveira</title>
    <description>The latest articles on DEV Community by Alef Ojeda de Oliveira (@nemuba).</description>
    <link>https://dev.to/nemuba</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F214941%2F5964545d-9699-4690-a30b-9e2328858860.jpeg</url>
      <title>DEV Community: Alef Ojeda de Oliveira</title>
      <link>https://dev.to/nemuba</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nemuba"/>
    <language>en</language>
    <item>
      <title>Competências Essenciais para um Desenvolvedor Ruby on Rails</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Mon, 17 Nov 2025 00:13:09 +0000</pubDate>
      <link>https://dev.to/nemuba/competencias-essenciais-para-um-desenvolvedor-ruby-on-rails-hmb</link>
      <guid>https://dev.to/nemuba/competencias-essenciais-para-um-desenvolvedor-ruby-on-rails-hmb</guid>
      <description>&lt;h2&gt;
  
  
  1. Fundamentos da Linguagem Ruby
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sintaxe, classes, módulos e mixins&lt;/li&gt;
&lt;li&gt;Orientação a objetos aplicada&lt;/li&gt;
&lt;li&gt;Blocks, Procs e Lambdas&lt;/li&gt;
&lt;li&gt;Enumeráveis e coleções&lt;/li&gt;
&lt;li&gt;Metaprogramação prática&lt;/li&gt;
&lt;li&gt;Tratamento de exceções&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Arquitetura Ruby on Rails
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MVC completo (Models, Views, Controllers)&lt;/li&gt;
&lt;li&gt;Active Record e callbacks&lt;/li&gt;
&lt;li&gt;Active Model e validations&lt;/li&gt;
&lt;li&gt;Active Support (concerns, inflectors, helpers)&lt;/li&gt;
&lt;li&gt;Action Controller e filtros&lt;/li&gt;
&lt;li&gt;Action View e helpers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Banco de Dados
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SQL avançado&lt;/li&gt;
&lt;li&gt;Migrations&lt;/li&gt;
&lt;li&gt;Associação entre modelos (belongs_to, has_many, has_one, has_many :through, etc.)&lt;/li&gt;
&lt;li&gt;Indexação, performance e EXPLAIN&lt;/li&gt;
&lt;li&gt;Transações e locking&lt;/li&gt;
&lt;li&gt;Uso de PostgreSQL (JSONB, CTEs, funções)&lt;/li&gt;
&lt;li&gt;Uso de Oracle/MySQL conforme necessidade&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Active Record Avançado
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Arel e construção de queries&lt;/li&gt;
&lt;li&gt;Scopes e ransackers&lt;/li&gt;
&lt;li&gt;Otimização: includes, preload, eager_load&lt;/li&gt;
&lt;li&gt;Joins complexos&lt;/li&gt;
&lt;li&gt;Queries com CTEs&lt;/li&gt;
&lt;li&gt;Estratégias de N+1&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. APIs e Serviços
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rails API mode&lt;/li&gt;
&lt;li&gt;Versionamento de API&lt;/li&gt;
&lt;li&gt;Serializers: Blueprinter, ActiveModelSerializers, JBuilder&lt;/li&gt;
&lt;li&gt;Autenticação e autorização (Devise, JWT, OAuth2, Cancancan, Pundit)&lt;/li&gt;
&lt;li&gt;Padrões REST e padrões de mercado&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Background Jobs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Active Job&lt;/li&gt;
&lt;li&gt;Sidekiq, Resque, Delayed Job&lt;/li&gt;
&lt;li&gt;Retries, idempotência e fila&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Testes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;RSpec e Minitest&lt;/li&gt;
&lt;li&gt;Testes unitários, de request, de modelo e integração&lt;/li&gt;
&lt;li&gt;Factories (FactoryBot)&lt;/li&gt;
&lt;li&gt;Mocking, stubbing e testes de serviços&lt;/li&gt;
&lt;li&gt;Cobertura de testes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Front-end Integrado
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hotwire (Turbo + Stimulus)&lt;/li&gt;
&lt;li&gt;ERB, HAML ou Slim&lt;/li&gt;
&lt;li&gt;Importmap ou Webpacker / Vite no legado&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. Segurança
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSRF, XSS, SQL Injection&lt;/li&gt;
&lt;li&gt;Sanitização de parâmetros&lt;/li&gt;
&lt;li&gt;Configurações de cookies e sessions&lt;/li&gt;
&lt;li&gt;Proteções nativas do Rails&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Deploy e Infraestrutura
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Docker e docker-compose&lt;/li&gt;
&lt;li&gt;Kubernetes e Helm charts&lt;/li&gt;
&lt;li&gt;Kamal&lt;/li&gt;
&lt;li&gt;DigitalOcean, Heroku, AWS (EC2, RDS, S3)&lt;/li&gt;
&lt;li&gt;Nginx/Apache&lt;/li&gt;
&lt;li&gt;CI/CD (GitHub Actions, GitLab CI, CircleCI)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11. Observabilidade
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Logs estruturados&lt;/li&gt;
&lt;li&gt;Monitoração (Grafana, Prometheus)&lt;/li&gt;
&lt;li&gt;Sentry, Bugsnag, Honeybadger&lt;/li&gt;
&lt;li&gt;Métricas e tracing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. Boas Práticas de Código
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SOLID aplicado ao Rails&lt;/li&gt;
&lt;li&gt;KISS, YAGNI, DRY&lt;/li&gt;
&lt;li&gt;Service Objects, Form Objects, Query Objects&lt;/li&gt;
&lt;li&gt;Decorators e Presenters&lt;/li&gt;
&lt;li&gt;Padrão Repository quando necessário&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  13. Arquiteturas Avançadas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Engines Rails e aplicações modulares&lt;/li&gt;
&lt;li&gt;Monolito modular&lt;/li&gt;
&lt;li&gt;Microservices (somente quando necessário)&lt;/li&gt;
&lt;li&gt;Event-driven architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  14. Performance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cache com Redis e Memcached&lt;/li&gt;
&lt;li&gt;HTTP caching&lt;/li&gt;
&lt;li&gt;Otimização de consultas&lt;/li&gt;
&lt;li&gt;Benchmarking e profiling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  15. Ferramentas comumente usadas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;rbenv, asdf ou RVM&lt;/li&gt;
&lt;li&gt;Bundler&lt;/li&gt;
&lt;li&gt;Rubocop&lt;/li&gt;
&lt;li&gt;Brakeman&lt;/li&gt;
&lt;li&gt;Overmind/Foreman&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  16. Modernizações
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rails 7+ Hotwire&lt;/li&gt;
&lt;li&gt;Rails 8 e Kamal&lt;/li&gt;
&lt;li&gt;ActiveRecord Async Queries&lt;/li&gt;
&lt;li&gt;Multi-DB e replicação&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  17. Cultura de Desenvolvimento
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitFlow, trunk-based e práticas de versionamento&lt;/li&gt;
&lt;li&gt;Pull Requests, code review&lt;/li&gt;
&lt;li&gt;Documentação de endpoints (RSwag, OAS-Rails)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  18. Conhecimentos Complementares
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Linux básico&lt;/li&gt;
&lt;li&gt;Redes e HTTP&lt;/li&gt;
&lt;li&gt;Noções de arquitetura de software&lt;/li&gt;
&lt;li&gt;Containerização&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  19. Carreira
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Júnior: fundamentos de Ruby, Rails, MVC, ActiveRecord, APIs simples&lt;/li&gt;
&lt;li&gt;Pleno: domínio de SQL, otimizações, serviços, testes, Docker&lt;/li&gt;
&lt;li&gt;Sênior: arquitetura, engines, escalabilidade, performance, liderança técnica&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>dev</category>
      <category>programmers</category>
    </item>
    <item>
      <title>Rails Helper Link: "link_to_if and link_to_unless"</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Mon, 03 Feb 2025 12:14:24 +0000</pubDate>
      <link>https://dev.to/nemuba/rails-helper-link-linktoif-and-linktounless-3mbg</link>
      <guid>https://dev.to/nemuba/rails-helper-link-linktoif-and-linktounless-3mbg</guid>
      <description>&lt;p&gt;&lt;strong&gt;Exploring the &lt;code&gt;link_to_if&lt;/code&gt; and &lt;code&gt;link_to_unless&lt;/code&gt; Helpers in Rails&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;link_to_if&lt;/code&gt; and &lt;code&gt;link_to_unless&lt;/code&gt; helpers in Ruby on Rails are valuable tools for conditionally generating links in your application. They help avoid unnecessary &lt;code&gt;if/else&lt;/code&gt; structures, making the code cleaner and more readable.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;link_to_if&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;link_to_if&lt;/code&gt; helper creates a link only if the provided condition is true; otherwise, it renders the specified alternative content.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= link_to_if user_signed_in?, "Profile", profile_path, class: "btn btn-primary" %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the user is logged in, the link to the profile will be generated. Otherwise, only the text "Profile" will be displayed without being a link.&lt;/p&gt;

&lt;p&gt;We can customize the content when the condition is false:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= link_to_if user_signed_in?, "Profile", profile_path do %&amp;gt;
  &amp;lt;span class=&lt;/span&gt;&lt;span class="s2"&gt;"text-muted"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;Log&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;link_to_unless&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;link_to_unless&lt;/code&gt; helper does the opposite of &lt;code&gt;link_to_if&lt;/code&gt;: it creates a link only if the condition is false. If the condition is true, it displays the content normally.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= link_to_unless admin?, "Request Access", request_access_path %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the user is &lt;strong&gt;not&lt;/strong&gt; an administrator, a link to "Request Access" will be generated. If the user is an administrator, the text will be displayed normally, without being a link.&lt;/p&gt;

&lt;p&gt;Similarly to &lt;code&gt;link_to_if&lt;/code&gt;, we can customize the alternative content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= link_to_unless admin?, "Request Access", request_access_path do %&amp;gt;
  &amp;lt;span class=&lt;/span&gt;&lt;span class="s2"&gt;"text-muted"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;You&lt;/span&gt; &lt;span class="n"&gt;already&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;administrator&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;These helpers are very useful for simplifying the logic of displaying links in Rails applications, avoiding the need for &lt;code&gt;if/else&lt;/code&gt; blocks in the template. This makes the code more elegant and easier to maintain.&lt;/p&gt;

&lt;p&gt;Did you like the tip? Share it with other developers! 🚀 &lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>helpers</category>
      <category>html</category>
    </item>
    <item>
      <title>Instalando Keycloak usando Docker</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Wed, 16 Oct 2024 02:11:05 +0000</pubDate>
      <link>https://dev.to/nemuba/instalando-keycloak-usando-docker-5h7o</link>
      <guid>https://dev.to/nemuba/instalando-keycloak-usando-docker-5h7o</guid>
      <description>&lt;h1&gt;
  
  
  Instalando o Keycloak Usando Docker
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Keycloak é uma ferramenta de gerenciamento de identidade e acesso que permite a autenticação e autorização de usuários em aplicações modernas. Ele é uma solução open-source que facilita o controle de segurança em diversos sistemas. Neste guia, vamos aprender a instalar o Keycloak utilizando Docker, de forma rápida e prática.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pré-requisitos
&lt;/h2&gt;

&lt;p&gt;Antes de começarmos, você precisa garantir que seu ambiente esteja preparado. Você precisará dos seguintes itens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt;: Certifique-se de ter o Docker instalado em sua máquina. Você pode verificar se ele está instalado executando o comando &lt;code&gt;docker --version&lt;/code&gt;. Caso não tenha, siga as instruções de instalação para o seu sistema operacional &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Passo 1: Baixar a Imagem do Keycloak
&lt;/h2&gt;

&lt;p&gt;Para instalar o Keycloak usando Docker, primeiro baixe a imagem oficial do Keycloak. Execute o seguinte comando no terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull quay.io/keycloak/keycloak:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este comando irá baixar a versão mais recente da imagem do Keycloak do repositório oficial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passo 2: Iniciar o Container do Keycloak
&lt;/h2&gt;

&lt;p&gt;Depois de baixar a imagem, você pode iniciar o Keycloak com o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;KEYCLOAK_ADMIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;KEYCLOAK_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin quay.io/keycloak/keycloak:latest start-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este comando possui as seguintes opções:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;-p 8080:8080&lt;/code&gt;&lt;/strong&gt;: Mapeia a porta 8080 do container para a porta 8080 do host, permitindo o acesso ao Keycloak pelo navegador.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;-e KEYCLOAK_ADMIN=admin&lt;/code&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;code&gt;-e KEYCLOAK_ADMIN_PASSWORD=admin&lt;/code&gt;&lt;/strong&gt;: Define o usuário administrador (&lt;code&gt;admin&lt;/code&gt;) e a senha (&lt;code&gt;admin&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;start-dev&lt;/code&gt;&lt;/strong&gt;: Inicia o Keycloak no modo de desenvolvimento, que é mais adequado para testes e configurações iniciais.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Passo 3: Acessar o Keycloak
&lt;/h2&gt;

&lt;p&gt;Depois de iniciar o container, você pode acessar o Keycloak pelo navegador. Basta ir para &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use o nome de usuário &lt;code&gt;admin&lt;/code&gt; e a senha &lt;code&gt;admin&lt;/code&gt; (ou a senha que você definiu) para fazer login no painel administrativo do Keycloak.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Passo 4: Configuração Básica
&lt;/h2&gt;

&lt;p&gt;Assim que estiver logado, você pode criar novos &lt;strong&gt;Realms&lt;/strong&gt; (ambientes de autenticação isolados, que contêm configurações, usuários e permissões), &lt;strong&gt;Clients&lt;/strong&gt; (aplicações que usam Keycloak para autenticação, como aplicativos web ou serviços backend) e configurar &lt;strong&gt;Usuários&lt;/strong&gt; (indivíduos que serão autenticados no sistema).&lt;/p&gt;

&lt;p&gt;Se precisar fazer ajustes mais avançados, recomendo explorar a documentação oficial do Keycloak: &lt;a href="https://www.keycloak.org/documentation" rel="noopener noreferrer"&gt;https://www.keycloak.org/documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passo 5: Como Criar um Realm
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;No painel administrativo do Keycloak, clique em &lt;strong&gt;Realms&lt;/strong&gt; no menu à esquerda.&lt;/li&gt;
&lt;li&gt;Clique em &lt;strong&gt;Add Realm&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Insira um nome para o novo Realm e clique em &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Um Realm permite que você isole a configuração de autenticação, usuários e permissões, facilitando a administração de diferentes ambientes ou aplicações.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passo 6: Como Criar um Client
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Dentro do Realm que você criou, clique em &lt;strong&gt;Clients&lt;/strong&gt; no menu à esquerda.&lt;/li&gt;
&lt;li&gt;Clique em &lt;strong&gt;Create&lt;/strong&gt; para adicionar um novo Client.&lt;/li&gt;
&lt;li&gt;Insira um identificador para o Client (como o nome da aplicação) e clique em &lt;strong&gt;Save&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Configure o &lt;strong&gt;Client Protocol&lt;/strong&gt; e outras configurações relevantes, como &lt;strong&gt;Access Type&lt;/strong&gt; (confira se deseja &lt;strong&gt;confidential&lt;/strong&gt; ou &lt;strong&gt;public&lt;/strong&gt;, dependendo do tipo de aplicação).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O Client representa uma aplicação que utilizará Keycloak para autenticação, como uma aplicação web ou um serviço backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passo 7: Como Criar um Usuário
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;No painel administrativo, clique em &lt;strong&gt;Users&lt;/strong&gt; no menu à esquerda.&lt;/li&gt;
&lt;li&gt;Clique em &lt;strong&gt;Add User&lt;/strong&gt; para criar um novo usuário.&lt;/li&gt;
&lt;li&gt;Preencha os campos obrigatórios, como &lt;strong&gt;Username&lt;/strong&gt;, e clique em &lt;strong&gt;Save&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Depois de salvar, vá até a aba &lt;strong&gt;Credentials&lt;/strong&gt; para definir uma senha para o usuário. Insira a senha desejada e clique em &lt;strong&gt;Set Password&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Com usuários criados, você poderá realizar testes de autenticação e configurar permissões específicas para cada um.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comandos Úteis
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Para parar o container&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  docker stop &amp;lt;container_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitua &lt;code&gt;&amp;lt;container_id&amp;gt;&lt;/code&gt; pelo ID do container que você deseja parar. Você pode obter o ID do container usando o comando &lt;code&gt;docker ps&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Para ver os logs&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  docker logs &lt;span class="nt"&gt;-f&lt;/span&gt; &amp;lt;container_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitua &lt;code&gt;&amp;lt;container_id&amp;gt;&lt;/code&gt; pelo ID do container para visualizar os logs em tempo real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerações Finais
&lt;/h2&gt;

&lt;p&gt;Utilizando o Docker, o Keycloak pode ser instalado de maneira muito rápida e prática. Como próximos passos, considere explorar integrações com outras ferramentas, como um servidor LDAP ou uma aplicação backend. Além disso, para ambientes de produção, é altamente recomendável configurar medidas de segurança adicionais, como o uso de certificados SSL e ajustes nas permissões de acesso. Com isso, você tem uma infraestrutura poderosa de autenticação pronta para ser integrada a seus projetos.&lt;/p&gt;

&lt;p&gt;Lembre-se de sempre manter o Keycloak e os componentes associados atualizados, garantindo assim maior segurança e estabilidade no seu sistema.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>keycloak</category>
      <category>authentication</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Ruby on Rails: Autenticação utilizando Devise + Keycloak</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Wed, 16 Oct 2024 01:56:36 +0000</pubDate>
      <link>https://dev.to/nemuba/ruby-on-rails-autenticacao-utilizando-devise-keycloak-12ae</link>
      <guid>https://dev.to/nemuba/ruby-on-rails-autenticacao-utilizando-devise-keycloak-12ae</guid>
      <description>&lt;p&gt;Se você deseja adicionar uma camada de autenticação robusta e simplificar o gerenciamento de usuários na sua aplicação Ruby on Rails, você está no lugar certo! Neste guia, vou te mostrar como integrar o Devise com o Keycloak de forma prática e direta, para que sua aplicação tenha uma autenticação segura e fácil de manter.&lt;/p&gt;

&lt;p&gt;Vamos começar juntos passo a passo, para garantir que tudo funcione perfeitamente e você consiga aproveitar o melhor dessas ferramentas.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Preparando o Ambiente
&lt;/h3&gt;

&lt;p&gt;Antes de começar, certifique-se de ter o &lt;a href="https://www.keycloak.org/" rel="noopener noreferrer"&gt;Keycloak&lt;/a&gt; rodando localmente ou em um servidor. Keycloak é uma solução de identidade e acesso muito poderosa que suporta autenticação via OAuth2 e OpenID Connect.&lt;/p&gt;

&lt;p&gt;Link guia basico: &lt;a href="https://dev.to/nemuba/instalando-keycloak-usando-docker-5h7o"&gt;Instalação Keycloak via Docker&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Adicionando Dependências ao Projeto
&lt;/h3&gt;

&lt;p&gt;No seu arquivo &lt;code&gt;Gemfile&lt;/code&gt;, adicione as seguintes gems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'devise'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'omniauth-keycloak'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'omniauth-rails_csrf_protection'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois, rode &lt;code&gt;bundle install&lt;/code&gt; para instalar as dependências.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Configurando o Devise
&lt;/h3&gt;

&lt;p&gt;Em seguida, configure o Devise. Se ainda não instalou o Devise na sua aplicação, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate devise:install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E depois crie um modelo de usuário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate devise User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Configurando o OmniAuth com Keycloak
&lt;/h3&gt;

&lt;p&gt;Você precisará adicionar uma configuração personalizada para o OmniAuth para que ele possa se comunicar com o Keycloak. No arquivo &lt;code&gt;config/initializers/devise.rb&lt;/code&gt;, configure o OmniAuth para usar o Keycloak:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# Outras configurações do Devise...&lt;/span&gt;

  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;omniauth&lt;/span&gt; &lt;span class="ss"&gt;:keycloak&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'CLIENT_ID'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'CLIENT_SECRET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="ss"&gt;client_options: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="ss"&gt;site: &lt;/span&gt;&lt;span class="s1"&gt;'https://SEU_DOMINIO_DO_KEYCLOAK/auth'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="ss"&gt;realm: &lt;/span&gt;&lt;span class="s1"&gt;'NOME_DO_SEU_REALM'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="ss"&gt;base_url: &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="ss"&gt;redirect_uri: &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000/users/auth/keycloakopenid/callback"&lt;/span&gt;
                  &lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="ss"&gt;provider_ignores_state: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="ss"&gt;scope: &lt;/span&gt;&lt;span class="s2"&gt;"openid,profile,email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="ss"&gt;strategy_class: &lt;/span&gt;&lt;span class="no"&gt;OmniAuth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Strategies&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;KeycloakOpenId&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitua &lt;code&gt;'CLIENT_ID'&lt;/code&gt;, &lt;code&gt;'CLIENT_SECRET'&lt;/code&gt;, &lt;code&gt;'SEU_DOMINIO_DO_KEYCLOAK'&lt;/code&gt; e &lt;code&gt;'NOME_DO_SEU_REALM'&lt;/code&gt; pelos valores apropriados para a sua configuração do Keycloak.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Atualizando as Rotas
&lt;/h3&gt;

&lt;p&gt;Você também precisa configurar as rotas para que o Devise possa lidar com a autenticação via OmniAuth. Além disso, você pode gerar o controller &lt;code&gt;omniauth_callbacks&lt;/code&gt; automaticamente com o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate devise:controllers &lt;span class="nb"&gt;users&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; omniauth_callbacks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No arquivo &lt;code&gt;config/routes.rb&lt;/code&gt;, adicione:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;devise_for&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;controllers: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;omniauth_callbacks: &lt;/span&gt;&lt;span class="s1"&gt;'users/omniauth_callbacks'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Criando o Callback Controller
&lt;/h3&gt;

&lt;p&gt;Você precisará criar um controller para lidar com os callbacks do OmniAuth. Crie o arquivo &lt;code&gt;app/controllers/users/omniauth_callbacks_controller.rb&lt;/code&gt; com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Users::OmniauthCallbacksController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;OmniauthCallbacksController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;keycloak&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_omniauth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'omniauth.auth'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;persisted?&lt;/span&gt;
      &lt;span class="n"&gt;sign_in_and_redirect&lt;/span&gt; &lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;event: :authentication&lt;/span&gt;
      &lt;span class="n"&gt;set_flash_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:notice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;kind: &lt;/span&gt;&lt;span class="s1"&gt;'Keycloak'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_navigational_format?&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'devise.keycloak_data'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'omniauth.auth'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;new_user_registration_url&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;failure&lt;/span&gt;
    &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;root_path&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Atualizando o Modelo User
&lt;/h3&gt;

&lt;p&gt;Finalmente, você precisará adicionar um método ao seu modelo &lt;code&gt;User&lt;/code&gt; para lidar com as informações recebidas do Keycloak:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;devise&lt;/span&gt; &lt;span class="ss"&gt;:database_authenticatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:registerable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="ss"&gt;:recoverable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:rememberable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:validatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="ss"&gt;:omniauthable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;omniauth_providers: &lt;/span&gt;&lt;span class="sx"&gt;%i[keycloak]&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_omniauth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;provider: &lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;uid: &lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first_or_create&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;
      &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;friendly_token&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Testando a Integração
&lt;/h3&gt;

&lt;p&gt;Com tudo configurado, você agora deve ser capaz de acessar a página de login e ver a opção para se autenticar com o Keycloak.&lt;/p&gt;

&lt;p&gt;Para testar a autenticação, você também pode criar um endpoint protegido que requer que o usuário esteja autenticado. Por exemplo, adicione o seguinte método no seu controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DashboardController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:authenticate_user!&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;plain: &lt;/span&gt;&lt;span class="s1"&gt;'Bem-vindo ao painel, você está autenticado!'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em &lt;code&gt;config/routes.rb&lt;/code&gt;, adicione a rota:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'dashboard'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'dashboard#index'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao acessar &lt;code&gt;/dashboard&lt;/code&gt; sem estar autenticado, você será redirecionado automaticamente para a página de login do Devise. Certifique-se de que as configurações do Keycloak estão corretas, incluindo o cliente configurado para suportar &lt;code&gt;redirect_uri&lt;/code&gt; adequado.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;A integração do Keycloak com Devise oferece uma solução segura e flexível para autenticação em aplicações Rails. Isso é especialmente útil para aplicações que precisam gerenciar autenticação de usuários em múltiplos sistemas.&lt;/p&gt;

&lt;p&gt;Se tiver alguma dúvida ou quiser mais detalhes sobre algum passo, deixe um comentário!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>devise</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Guia básico sobre lambda em Ruby</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Wed, 15 Mar 2023 01:26:16 +0000</pubDate>
      <link>https://dev.to/nemuba/guia-basico-sobre-lambda-em-ruby-3o0d</link>
      <guid>https://dev.to/nemuba/guia-basico-sobre-lambda-em-ruby-3o0d</guid>
      <description>&lt;p&gt;Lambdas em Ruby são objetos que representam funções anônimas. Eles são úteis quando você precisa passar uma função como argumento para outra função ou quando deseja criar funções curtas e expressivas. Aqui está um guia prático sobre como usar lambdas em Ruby:&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando uma lambda
&lt;/h2&gt;

&lt;p&gt;Lambdas são criados usando a palavra-chave lambda ou -&amp;gt;. Aqui está um exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# ou&lt;/span&gt;
&lt;span class="n"&gt;my_lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora my_lambda é um objeto que representa uma função que multiplica seu argumento por 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chamando uma lambda
&lt;/h2&gt;

&lt;p&gt;Lambdas são chamados da mesma forma que uma função normal, usando a sintaxe lambda.call(argumento) ou simplesmente lambda(argumento). Aqui está um exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="c1"&gt;# output: 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou ainda, mais curto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_lambda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="c1"&gt;# output: 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Passando uma lambda como argumento
&lt;/h2&gt;

&lt;p&gt;Lambdas são frequentemente usados como argumentos de outras funções. Isso é especialmente útil quando você deseja passar uma função personalizada para uma função de ordem superior (como map, filter ou reduce). Aqui está um exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# A função double_values aplica a função lambda em cada elemento do array&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;double_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;valores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;double_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_lambda&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="c1"&gt;# output: [2, 4, 6, 8]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Capturando variáveis em uma lambda
&lt;/h2&gt;

&lt;p&gt;Lambdas também podem capturar variáveis do escopo em que foram criados. Isso pode ser útil para criar funções que têm acesso a variáveis locais ou de instância. Aqui está um exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_lambda&lt;/span&gt;
  &lt;span class="n"&gt;mensagem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Olá, mundo!"&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;mensagem&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Cria uma lambda que imprime "Olá, mundo!"&lt;/span&gt;
&lt;span class="n"&gt;my_lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_lambda&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse exemplo, a lambda captura a variável mensagem do escopo em que foi criada. Quando a lambda é chamada, ela imprime a mensagem "Olá, mundo!".&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;As lambdas em Ruby são objetos poderosos que podem ajudar a tornar seu código mais conciso e expressivo. Com este guia prático, você deve ter uma boa compreensão de como criar, chamar e passar lambdas como argumentos. Experimente criar suas próprias lambdas e usá-las em suas funções!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>How use the gem 'run_database_backup'</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Sat, 25 Feb 2023 12:45:12 +0000</pubDate>
      <link>https://dev.to/nemuba/how-use-the-gem-rundatabasebackup-530b</link>
      <guid>https://dev.to/nemuba/how-use-the-gem-rundatabasebackup-530b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Data is a critical aspect of any application, and it's essential to have a reliable backup strategy in place to protect your data in case of a disaster or data loss. Fortunately, the "run_database_backup" gem provides an easy way to create backups of your MongoDB, PostgreSQL, and MySQL databases from within your Rails application.&lt;/p&gt;

&lt;p&gt;In this guide, we'll walk you through the basic steps for using the "run_database_backup" gem to create backups of your databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;Add the "run_database_backup" gem to your Gemfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;gem 'run_database_backup'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the gem by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add the three backup tasks to your application.&lt;/p&gt;

&lt;p&gt;To create a backup of your MongoDB database, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails mongo:backup[uri,database_name,backup_directory]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace "uri" with the URI for your MongoDB database (e.g. "mongodb://localhost:27017"), "database_name" with the name of the MongoDB database you want to back up, and "backup_directory" with the directory where you want to store the backup file.&lt;/p&gt;

&lt;p&gt;For example, to create a backup of a MongoDB database called "app_database" running on the local machine and store the backup file in the "./tmp" directory, you would run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails mongo:backup[&lt;span class="s1"&gt;'mongodb://localhost:27017'&lt;/span&gt;,&lt;span class="s1"&gt;'app_database'&lt;/span&gt;,&lt;span class="s1"&gt;'./tmp'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create a backup of your PostgreSQL database, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails postgresql:backup[uri,database_name,backup_directory]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace "uri" with the URI for your PostgreSQL database (e.g. "postgresql://localhost"), "database_name" with the name of the PostgreSQL database you want to back up, and "backup_directory" with the directory where you want to store the backup file.&lt;/p&gt;

&lt;p&gt;For example, to create a backup of a PostgreSQL database called "app_database" running on the local machine and store the backup file in the "./tmp" directory, you would run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails postgresql:backup[&lt;span class="s1"&gt;'postgresql://localhost'&lt;/span&gt;,&lt;span class="s1"&gt;'app_database'&lt;/span&gt;,&lt;span class="s1"&gt;'./tmp'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that you will need to have the "pg_dump" utility installed on your machine in order to create a backup of a PostgreSQL database.&lt;/p&gt;

&lt;p&gt;To create a backup of your MySQL database, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails mysql:backup[uri,database_name,backup_directory]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace "uri" with the URI for your MySQL database (e.g. "mysql2://localhost"), "database_name" with the name of the MySQL database you want to back up, and "backup_directory" with the directory where you want to store the backup file.&lt;/p&gt;

&lt;p&gt;For example, to create a backup of a MySQL database called "app_database" running on the local machine and store the backup file in the "./tmp" directory, you would run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails mysql:backup[&lt;span class="s1"&gt;'mysql2://localhost'&lt;/span&gt;,&lt;span class="s1"&gt;'app_database'&lt;/span&gt;,&lt;span class="s1"&gt;'./tmp'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that you will need to have the "mysqldump" utility installed on your machine in order to create a backup of a MySQL database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this guide, we've walked you through the basic steps for using the "run_database_backup" gem to create backups of your MongoDB, PostgreSQL, and MySQL databases from within your Rails application. By following these steps, you can quickly and easily create backups of your databases to protect your data in case of a disaster or data loss.&lt;/p&gt;

&lt;p&gt;Remember to store your backup files in a secure location and to regularly test your backup strategy to ensure that you can restore your data when you need it.&lt;/p&gt;

&lt;p&gt;To learn more about the "run_database_backup" gem, visit the gem's repository on GitHub: &lt;a href="https://github.com/nemuba/run_database_backup"&gt;https://github.com/nemuba/run_database_backup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy backing up!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>database</category>
      <category>programming</category>
    </item>
    <item>
      <title>Pattern Service Objects em Ruby</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Fri, 24 Feb 2023 00:33:47 +0000</pubDate>
      <link>https://dev.to/nemuba/pattern-service-objects-em-ruby-27l2</link>
      <guid>https://dev.to/nemuba/pattern-service-objects-em-ruby-27l2</guid>
      <description>&lt;p&gt;O padrão de design Service Objects é uma técnica útil e popular em Ruby on Rails para gerenciar a lógica de negócios complexa em seus aplicativos. O objetivo deste padrão é separar a lógica de negócios do controlador ou modelo e colocá-la em classes independentes chamadas de Service Objects. Esses objetos de serviço são responsáveis por executar uma tarefa específica ou um conjunto de tarefas relacionadas, tornando o código mais modular, legível e fácil de testar.&lt;/p&gt;

&lt;p&gt;Vamos ver como implementar o padrão Service Objects em Ruby on Rails com um exemplo prático.&lt;/p&gt;

&lt;p&gt;Suponha que temos um aplicativo que permite aos usuários reservar quartos de hotel. Quando um usuário faz uma reserva, precisamos verificar se o quarto está disponível e, em seguida, atualizar a disponibilidade do quarto e criar um registro de reserva no banco de dados.&lt;/p&gt;

&lt;p&gt;Em vez de colocar toda a lógica de reserva em um controlador ou modelo, podemos criar um Service Object chamado ReservationService para gerenciar o processo de reserva. Aqui está um exemplo de implementação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReservationService&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@room&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;room&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="vi"&gt;@start_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_date&lt;/span&gt;
    &lt;span class="vi"&gt;@end_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end_date&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;ArgumentError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Room is not available for these dates'&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;room_available?&lt;/span&gt;

    &lt;span class="n"&gt;create_reservation&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:end_date&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;room_available?&lt;/span&gt;
    &lt;span class="c1"&gt;# Check if room is available for the given dates&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="no"&gt;Reservation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;room: &lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_date&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;end_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_reservation&lt;/span&gt;
    &lt;span class="c1"&gt;# Create reservation record in the database&lt;/span&gt;
    &lt;span class="no"&gt;Reservation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;room: &lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;start_date: &lt;/span&gt;&lt;span class="n"&gt;start_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;end_date: &lt;/span&gt;&lt;span class="n"&gt;end_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo, o construtor do ReservationService recebe o quarto, o usuário e as datas de início e término da reserva. O método call é o ponto de entrada para o Service Object e é responsável por executar as tarefas de reserva.&lt;/p&gt;

&lt;p&gt;O método room_available? verifica se o quarto está disponível para as datas da reserva. Ele usa a consulta ActiveRecord exists? para verificar se há alguma reserva que esteja ocorrendo durante as datas solicitadas.&lt;/p&gt;

&lt;p&gt;O método create_reservation é responsável por criar o registro de reserva no banco de dados usando o modelo Reservation.&lt;/p&gt;

&lt;p&gt;Agora, podemos chamar o ReservationService no controlador para processar as solicitações de reserva:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReservationsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@room&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Room&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:room_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="vi"&gt;@reservation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ReservationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:start_date&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:end_date&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@reservation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;persisted?&lt;/span&gt;
      &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:notice&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Reservation successfully created'&lt;/span&gt;
      &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="vi"&gt;@reservation&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:alert&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Error creating reservation'&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="s1"&gt;'rooms/show'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo, o controlador chama o ReservationService com o quarto, o usuário atual e as datas de início e término da reserva. Se a reserva for criada com sucesso, o usuário é redirecionado para a página de detalhes da reserva. Caso contrário, uma mensagem de erro é exibida.&lt;/p&gt;

&lt;p&gt;Conclusão:&lt;/p&gt;

&lt;p&gt;O padrão de design Service Objects é uma técnica poderosa para manter a lógica de negócios do seu aplicativo separada do controlador ou modelo. Isso ajuda a tornar seu código mais modular, legível e fácil de testar. Além disso, ele oferece uma solução escalável e flexível para gerenciar a lógica de negócios complexa.&lt;/p&gt;

&lt;p&gt;No exemplo acima, criamos um Service Object chamado ReservationService para gerenciar o processo de reserva de quartos de hotel. Ao separar a lógica de negócios em um objeto separado, podemos testá-lo de forma isolada e alterá-lo sem afetar o resto do código. Isso torna o processo de desenvolvimento mais eficiente e mais fácil de manter.&lt;/p&gt;

&lt;p&gt;Embora este exemplo seja específico para reservas de quartos de hotel, você pode usar o padrão Service Objects para gerenciar qualquer tipo de lógica de negócios em seu aplicativo. Espero que este exemplo prático ajude você a entender melhor como usar o padrão de design Service Objects em seus projetos Ruby on Rails.&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Ruby - Similarity</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Thu, 19 Jan 2023 18:12:14 +0000</pubDate>
      <link>https://dev.to/nemuba/ruby-similarity-3gl4</link>
      <guid>https://dev.to/nemuba/ruby-similarity-3gl4</guid>
      <description>&lt;p&gt;Existem várias maneiras de fazer comparação de similaridade entre strings em Ruby. Algumas das maneiras mais comuns incluem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Levenshtein distance:&lt;/strong&gt; É uma medida da distância entre duas strings, baseada na quantidade mínima de operações (inserção, deleção ou substituição de um caractere) necessárias para transformar uma string em outra. A biblioteca &lt;code&gt;text&lt;/code&gt; possui um método levenshtein_distance que pode ser usado para calcular a distância de Levenshtein entre duas strings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Jaro-Winkler distance:&lt;/strong&gt; É uma medida da similaridade entre duas strings, baseada na quantidade de caracteres comuns nas primeiras posições das strings e na distância entre os caracteres comuns. A biblioteca &lt;code&gt;amatch&lt;/code&gt; possui um método jaro_winkler que pode ser usado para calcular a distância de Jaro-Winkler entre duas strings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cosine similarity:&lt;/strong&gt; É uma medida da similaridade entre duas strings baseada no cosseno do ângulo entre vetores que representam as strings. A biblioteca &lt;code&gt;text-similarity&lt;/code&gt; possui um método cosine_similarity que pode ser usado para calcular a similaridade cosseno entre duas strings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fuzzy matching:&lt;/strong&gt; É uma técnica de correspondência aproximada que permite comparar duas strings e encontrar similaridades, mesmo se elas não forem idênticas. A biblioteca &lt;code&gt;fuzzy_match&lt;/code&gt; é uma boa opção para fazer correspondência fuzzy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shingling:&lt;/strong&gt; É uma técnica de comparação de strings baseada em dividir as strings em conjuntos de caracteres consecutivos (shingles) e comparando a presença desses conjuntos entre as strings. A biblioteca &lt;code&gt;shingles&lt;/code&gt; é uma boa opção para fazer comparação de similaridade baseado em shingling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essas são algumas das maneiras mais comuns de fazer comparação de similaridade entre strings em Ruby, mas existem outras técnicas e bibliotecas disponíveis. É importante escolher a técnica e a biblioteca mais adequadas para o seu caso de uso específico.&lt;/p&gt;

&lt;p&gt;A técnica mais utilizada para comparação de similaridade entre strings varia de acordo com o caso de uso específico e as necessidades do projeto.&lt;/p&gt;

&lt;p&gt;A distância de Levenshtein é amplamente utilizada para a comparação de strings curtas e é uma boa escolha para casos onde a precisão é mais importante do que a velocidade de processamento.&lt;/p&gt;

&lt;p&gt;A distância de Jaro-Winkler é amplamente utilizada para a comparação de strings de nomes e é uma boa escolha para casos onde as strings são similares mas não são idênticas.&lt;/p&gt;

&lt;p&gt;A Similaridade Cosseno é amplamente utilizada para a comparação de strings longas e é uma boa escolha para casos onde se deseja comparar documentos inteiros e encontrar similaridades entre eles.&lt;/p&gt;

&lt;p&gt;Fuzzy matching é amplamente utilizada para a comparação de strings quando a precisão não é tão importante e é uma boa escolha para casos onde as strings podem conter erros de digitação ou variações.&lt;/p&gt;

&lt;p&gt;Shingling é amplamente utilizada para a comparação de strings longas e é uma boa escolha para casos onde se deseja comparar documentos inteiros e encontrar similaridades entre eles.&lt;/p&gt;

&lt;p&gt;É importante notar que cada técnica tem suas próprias limitações e vantagens e a escolha da técnica certa dependerá do seu caso de uso específico.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplos
&lt;/h2&gt;

&lt;p&gt;Para ficar mais ilustrativo aqui estão alguns exemplos de código Ruby que ilustram como calcular a similaridade entre strings usando as técnicas mencionadas anteriormente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Levenshtein distance:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'text'&lt;/span&gt;
&lt;span class="n"&gt;string1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"kitten"&lt;/span&gt;
&lt;span class="n"&gt;string2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sitting"&lt;/span&gt;
&lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Levenshtein&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"The Levenshtein distance between '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' and '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Jaro-Winkler distance:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'amatch'&lt;/span&gt;
&lt;span class="n"&gt;string1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"DWAYNE"&lt;/span&gt;
&lt;span class="n"&gt;string2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"DUANE"&lt;/span&gt;
&lt;span class="n"&gt;jaro&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Amatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Jaro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jaro&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"The Jaro-Winkler distance between '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' and '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Cosine similarity:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'text-similarity'&lt;/span&gt;
&lt;span class="n"&gt;string1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"This is a test"&lt;/span&gt;
&lt;span class="n"&gt;string2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"This is a trial"&lt;/span&gt;
&lt;span class="n"&gt;cosine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TextSimilarity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CosineSimilarity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;similarity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cosine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSimilarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"The cosine similarity between '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' and '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;similarity&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Fuzzy matching:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'fuzzy_match'&lt;/span&gt;
&lt;span class="n"&gt;string1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;
&lt;span class="n"&gt;string2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"fuzi"&lt;/span&gt;
&lt;span class="n"&gt;fuzzy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FuzzyMatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fuzzy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"The fuzzy matching between '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' and '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Shingling:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'shingles'&lt;/span&gt;
&lt;span class="n"&gt;string1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"This is a test"&lt;/span&gt;
&lt;span class="n"&gt;string2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"This is a trial"&lt;/span&gt;
&lt;span class="n"&gt;shingle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Shingles&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Shingle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;shingle2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Shingles&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Shingle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;jaccard_distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shingle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shingle2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"The jaccard distance between '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' and '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;string2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;jaccard_distance&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Considerações finais
&lt;/h3&gt;

&lt;p&gt;Tenha em mente que esses são apenas exemplos básicos e você pode precisar personalizar esses códigos para atender às suas necessidades específicas. E também lembre-se de que essas bibliotecas podem ter dependências e precisam ser instaladas.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>architecture</category>
      <category>opensource</category>
      <category>career</category>
    </item>
    <item>
      <title>Otimizando consultas no banco de dados com o Rails</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Tue, 10 Jan 2023 00:55:10 +0000</pubDate>
      <link>https://dev.to/nemuba/otimizando-consultas-no-banco-de-dados-com-o-rails-35kj</link>
      <guid>https://dev.to/nemuba/otimizando-consultas-no-banco-de-dados-com-o-rails-35kj</guid>
      <description>&lt;p&gt;O desempenho de um aplicativo é crucial para a experiência do usuário final e uma das principais áreas onde é possível fazer otimizações é na consulta ao banco de dados. O Ruby on Rails possui várias ferramentas embutidas que podem ajudar a minimizar o tempo de resposta das consultas e, consequentemente, melhorar o desempenho do aplicativo.&lt;/p&gt;

&lt;p&gt;Uma das maneiras mais simples de otimizar consultas é através do uso de índices. Índices são estruturas de dados que são criadas em cima de uma ou mais colunas em uma tabela e servem para acelerar as buscas em um banco de dados. Por exemplo, se você tem uma tabela de usuários com milhões de linhas e precisa fazer uma consulta com base no e-mail do usuário, criar um índice na coluna de e-mail pode fazer com que a consulta seja muito mais rápida. Para criar um índice em uma coluna no banco de dados do Rails, basta adicionar a seguinte linha no seu modelo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="c1"&gt;# Adiciona um índice na coluna de e-mail&lt;/span&gt;
  &lt;span class="n"&gt;add_index&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outra maneira de otimizar consultas é através do uso de joins. Joins permitem que você faça consultas que combinam dados de duas ou mais tabelas. No entanto, é importante tomar cuidado ao utilizar joins, pois eles podem resultar em consultas muito lentas se não forem escritos de maneira eficiente. Por exemplo, a seguinte consulta utiliza um join ineficiente para obter os nomes dos usuários e os títulos de todos os posts que eles escreveram:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Consulta ineficiente&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:posts&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"users.name, posts.title"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em vez disso, você pode utilizar uma subconsulta para obter os mesmos resultados de maneira mais eficiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Consulta mais eficiente&lt;/span&gt;
&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"users.name"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"INNER JOIN (SELECT * FROM posts) AS posts ON posts.user_id = users.id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outra técnica útil para otimizar consultas é a utilização de tabelas temporárias. Às vezes, você pode precisar fazer uma consulta complexa que envolva muitas tabelas e operações. Em vez de escrever uma consulta complexa de uma só vez, você pode criar uma tabela temporária com os dados intermediários e, em seguida, fazer uma consulta mais simples na tabela temporária. Isso pode ajudar a reduzir o tempo de resposta da consulta, pois o banco de dados não precisa calcular os dados intermediários toda vez que a consulta é executada.&lt;/p&gt;

&lt;p&gt;Por exemplo, suponha que você queira obter a média de todas as notas de um conjunto de estudantes. Em vez de calcular a média com uma única consulta, você pode criar uma tabela temporária com as notas de cada estudante e, em seguida, calcular a média dessa tabela:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Cria uma tabela temporária com as notas de cada estudante&lt;/span&gt;
&lt;span class="no"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"CREATE TEMPORARY TABLE student_averages AS (SELECT student_id, AVG(grade) as average FROM grades GROUP BY student_id)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Calcula a média geral das notas&lt;/span&gt;
&lt;span class="n"&gt;overall_average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SELECT AVG(average) FROM student_averages"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essas são apenas algumas das maneiras de otimizar consultas no banco de dados com o Ruby on Rails. Existem muitas outras técnicas e ferramentas disponíveis, como o uso de cache, otimização de consultas explícitas e o uso de ferramentas de otimização de consultas, como o EXPLAIN. Utilizar essas técnicas pode ajudar a garantir que o seu aplicativo Ruby on Rails tenha um desempenho otimizado e uma experiência do usuário excelente.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>development</category>
      <category>discuss</category>
    </item>
    <item>
      <title>SimpleTask using Ruby on Rails 7, Stimulus and TailwindCSS</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Thu, 30 Dec 2021 15:36:38 +0000</pubDate>
      <link>https://dev.to/nemuba/simpletask-using-ruby-on-rails-7-stimulus-and-tailwindcss-1jdf</link>
      <guid>https://dev.to/nemuba/simpletask-using-ruby-on-rails-7-stimulus-and-tailwindcss-1jdf</guid>
      <description>&lt;p&gt;I created a SPA application to manage tasks using Ruby on Rails 7.&lt;/p&gt;

&lt;p&gt;This project was just to study the new framework pattern with turbo-rails and stimulus-js.&lt;/p&gt;

&lt;p&gt;It was an incredible experience, I found it very simple to develop with it!&lt;/p&gt;

&lt;p&gt;Follow the link below from github with the code!&lt;/p&gt;

&lt;p&gt;Hugs !&lt;br&gt;
Link Heroku: &lt;a href="http://simple-task-hotwire.herokuapp.com"&gt;http://simple-task-hotwire.herokuapp.com&lt;/a&gt;&lt;br&gt;
Link Github: &lt;a href="https://github.com/nemuba/simple_task"&gt;https://github.com/nemuba/simple_task&lt;/a&gt;&lt;br&gt;
Twitter: &lt;a href="https://twitter.com/OjedaAlef"&gt;https://twitter.com/OjedaAlef&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>hotwire</category>
      <category>tailwindcss</category>
      <category>stimulus</category>
    </item>
    <item>
      <title>Listing all tables and listing the columns of a respective database table of the a rails application!</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Tue, 30 Nov 2021 19:10:39 +0000</pubDate>
      <link>https://dev.to/nemuba/listing-all-tables-and-listing-the-columns-of-a-respective-database-table-of-the-a-rails-application-106h</link>
      <guid>https://dev.to/nemuba/listing-all-tables-and-listing-the-columns-of-a-respective-database-table-of-the-a-rails-application-106h</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GKcRJP5W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uhjcfojw7t1vcagwa5jm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GKcRJP5W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uhjcfojw7t1vcagwa5jm.png" alt="Code Rails console" width="880" height="761"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>database</category>
      <category>tips</category>
    </item>
    <item>
      <title>How to create download button for CSV and PDF using Ruby on Rails</title>
      <dc:creator>Alef Ojeda de Oliveira</dc:creator>
      <pubDate>Sat, 20 Nov 2021 16:01:12 +0000</pubDate>
      <link>https://dev.to/nemuba/how-to-create-download-button-for-csv-and-pdf-using-ruby-on-rails-135h</link>
      <guid>https://dev.to/nemuba/how-to-create-download-button-for-csv-and-pdf-using-ruby-on-rails-135h</guid>
      <description>&lt;h3&gt;
  
  
  Hey Guys !
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Let's cut to the chase, hands on code !
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;First generate scaffold
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;rails&lt;/span&gt; g scaffold Note title
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;run db:migrate
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;rails&lt;/span&gt; db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;now we are going to install the gem to generate PDF, we will use the gem 'prawn' and the 'prawn-table':
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;bundle&lt;/span&gt; add prawn prawn-table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;now we're going to add the route and buttons for downloads nor csv and pdf format:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# add route in file config/routes.rb&lt;/span&gt;
&lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:notes&lt;/span&gt;
&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="s1"&gt;'notes#index'&lt;/span&gt;
&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s1"&gt;'download/notes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'notes#download'&lt;/span&gt;

&lt;span class="c1"&gt;# add method downlod in controller app/controllers/notes_controller.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;download&lt;/span&gt;
    &lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;csv&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;send_data&lt;/span&gt; &lt;span class="no"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_csv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;filename: &lt;/span&gt;&lt;span class="s2"&gt;"notes-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.csv"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;send_data&lt;/span&gt; &lt;span class="no"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_pdf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;filename: &lt;/span&gt;&lt;span class="s2"&gt;"notes-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pdf"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# adds concerns to the note model to export the data&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Note&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ExportCsv&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;ExportPdf&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# now let's create the modules in app/models/concerns&lt;/span&gt;
&lt;span class="c1"&gt;# first export_csv.rb&lt;/span&gt;
&lt;span class="c1"&gt;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="c1"&gt;# module ExportCSV&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ExportCsv&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;

  &lt;span class="c1"&gt;# module ClassMethods&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_csv&lt;/span&gt;
      &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'csv'&lt;/span&gt;
      &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;col_sep: &lt;/span&gt;&lt;span class="s1"&gt;';'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;encoding: &lt;/span&gt;&lt;span class="s1"&gt;'utf-8'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%i[id title]&lt;/span&gt;

      &lt;span class="no"&gt;CSV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;headers: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;

        &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;csv&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# second export_pdf.rb&lt;/span&gt;
&lt;span class="c1"&gt;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="c1"&gt;# module ExportPdf&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ExportPdf&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Concern&lt;/span&gt;

  &lt;span class="c1"&gt;# module ClassMethods&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ClassMethods&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_pdf&lt;/span&gt;
      &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'prawn'&lt;/span&gt;
      &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'prawn/table'&lt;/span&gt;

      &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;position: :center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;column_widths: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;width: &lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%w[ID Title]&lt;/span&gt;
      &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="no"&gt;Prawn&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="s1"&gt;'All Notes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;align: :center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;size: &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;style: :bold&lt;/span&gt;
        &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;header: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# and finally add the links on the app/views/notes/index.html.erb page&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= button_to "Download CSV", download_notes_path(request.params.merge(format: :csv)), data: {turbo: :false} %&amp;gt;
&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;button_to&lt;/span&gt; &lt;span class="s2"&gt;"Download PDF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;download_notes_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;format: :pdf&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;turbo: :false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it, we're done!&lt;/p&gt;

&lt;p&gt;Github source: &lt;a href="https://github.com/nemuba/import_export_file_rails"&gt;https://github.com/nemuba/import_export_file_rails&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>csv</category>
      <category>pdf</category>
    </item>
  </channel>
</rss>
