<?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>Forem: Diogo Viana</title>
    <description>The latest articles on Forem by Diogo Viana (@diogoviana19).</description>
    <link>https://forem.com/diogoviana19</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%2F1503727%2Fa66cfc05-747d-4efb-9b66-df633cfd311d.jpg</url>
      <title>Forem: Diogo Viana</title>
      <link>https://forem.com/diogoviana19</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/diogoviana19"/>
    <language>en</language>
    <item>
      <title>Quick Rails Tip: Change Database Adapter</title>
      <dc:creator>Diogo Viana</dc:creator>
      <pubDate>Fri, 05 Dec 2025 23:31:35 +0000</pubDate>
      <link>https://forem.com/diogoviana19/quick-rails-tip-change-database-adapter-4ooo</link>
      <guid>https://forem.com/diogoviana19/quick-rails-tip-change-database-adapter-4ooo</guid>
      <description>&lt;h2&gt;
  
  
  The magic command
&lt;/h2&gt;

&lt;p&gt;Rails introduced a command a while back that simplifies database adapter changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails db:system:change &lt;span class="nt"&gt;--to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What does this command do
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Updates the Gemfile&lt;/strong&gt; - Adds/removes the necessary gems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modifies the database.yml&lt;/strong&gt; - Configures the new connections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generates the migrations&lt;/strong&gt; - Creates the migration files for the new database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Updates the configurations&lt;/strong&gt; - Adjusts the schema.rb and other files&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  More practical examples
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Changing from SQLite to PostgreSQL&lt;/span&gt;
rails db:system:change &lt;span class="nt"&gt;--to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql

&lt;span class="c"&gt;# Changing to MySQL&lt;/span&gt;
rails db:system:change &lt;span class="nt"&gt;--to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mysql

&lt;span class="c"&gt;# Going back to SQLite&lt;/span&gt;
rails db:system:change &lt;span class="nt"&gt;--to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sqlite3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Important considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always backup!&lt;/strong&gt; - Backup your data before making changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test in development&lt;/strong&gt; - Never test in production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check data types&lt;/strong&gt; - Some types may need adjustments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies&lt;/strong&gt; - Make sure you have the database installed on your machine (or Dockerfile)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Rails is full of hidden gems, and this is one of them. I think it's super useful, especially when you start a small project with SQLite and then want to migrate to PostgreSQL, for example.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>database</category>
      <category>sqlite</category>
      <category>quicktip</category>
    </item>
    <item>
      <title>Por que seus pull requests devem ser pequenos</title>
      <dc:creator>Diogo Viana</dc:creator>
      <pubDate>Mon, 28 Apr 2025 23:15:37 +0000</pubDate>
      <link>https://forem.com/diogoviana19/pt-br-porque-seus-pull-requests-devem-ser-pequenos-4e22</link>
      <guid>https://forem.com/diogoviana19/pt-br-porque-seus-pull-requests-devem-ser-pequenos-4e22</guid>
      <description>&lt;h2&gt;
  
  
  Motivação
&lt;/h2&gt;

&lt;p&gt;Tudo começou quando percebi um padrão preocupante no meu trabalho atual: os desenvolvedores demoravam muito mais tempo para revisar PRs grandes. Curioso com essa situação, decidi fazer uma pesquisa(interna) com a equipe para entender melhor o problema. A resposta foi unânime: quando um PR era grande, os desenvolvedores precisavam de um período significativo de tempo para fazer uma revisão adequada, o que significava interromper o trabalho que estavam fazendo. Isso criava um bloqueio muito grande para o autor do PR.&lt;/p&gt;

&lt;p&gt;Por outro lado, quando os PRs eram pequenos, a história era completamente diferente. Os desenvolvedores paravam o que estavam fazendo para fazer a revisão rapidamente, mantendo o fluxo de trabalho ágil e eficiente.&lt;/p&gt;

&lt;p&gt;Com os resultados em mão, decidimos estabelecer um limite prático: máximo de 15 arquivos alterados por PR. Para monitorar e melhorar essa prática, implementamos uma GitHub Action que adicionava automaticamente um label "too large" em PRs que excediam esse limite. No início, o número de PRs com esse label era alarmante, mas isso nos deu uma métrica clara para acompanhar nossa evolução.&lt;/p&gt;

&lt;p&gt;Com o tempo(e muita insistência da minha parte) a equipe começou a se adaptar à nova cultura de PRs pequenos. Hoje, é raro ver um PR com o label "too large", e o processo de revisão flui muito mais suavemente. Esta experiência me mostrou na prática o valor de manter PRs pequenos e focados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quais os reais benefícios percebidos?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Revisões Mais Rápidas e Eficientes
&lt;/h3&gt;

&lt;p&gt;PRs menores são mais fáceis de revisar. Enquanto um PR grande pode exigir um período de tempo significativo para revisão, PRs pequenos podem ser revisados em intervalos curtos, tornando o processo mais ágil e menos oneroso para os revisores.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Maior Qualidade nas Revisões
&lt;/h3&gt;

&lt;p&gt;Com menos código para analisar, os revisores podem se concentrar melhor em potenciais problemas com mais precisão. Em PRs grandes, é comum que pontos importantes passem despercebidos devido à sobrecarga de informações.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Menor Probabilidade de Bugs
&lt;/h3&gt;

&lt;p&gt;Mudanças menores são mais fáceis de testar e validar. Tanto o autor quanto o revisor conseguem entender melhor o impacto das alterações, reduzindo a chance de introduzir bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Código modular
&lt;/h3&gt;

&lt;p&gt;A necessidade de escrever código em pequenos pedaços naturalmente leva a um design mais modular e desacoplado, pois você é forçado a pensar em como dividir a funcionalidade em partes menores e mais coesas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como escrever PRs pequenos
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Sempre pense em pré-mudanças, mudanças e pós-mudanças. Em outras palavras, não escreva uma feature completa em &lt;strong&gt;UM ÚNICO PR&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Novos arquivos devem ser adicionados separadamente com antecedência se estiverem misturados com outras mudanças.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Separe as refatorações em PRs diferentes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Escreva código desacoplado que possa ser "deployado" a qualquer momento.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Muita gente trabalha com sistema de tickets(como JIRA) e normalmente as pessoas criam um PR para um ticket, o que pode ser um problema se o ticket for para uma feature grande. &lt;strong&gt;O ideal é que você crie vários PRs para um ticket&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quando PRs grandes são aceitáveis?
&lt;/h2&gt;

&lt;p&gt;Existem algumas situações onde PRs maiores podem ser justificáveis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remoção de arquivos inteiros&lt;/li&gt;
&lt;li&gt;Mudanças que são intrinsecamente grandes e não podem ser divididas&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Manter PRs pequenos não é apenas uma boa prática, é uma estratégia que beneficia toda a equipe. Aumenta a qualidade do código, acelera o processo de revisão e reduz a probabilidade de erros. Embora possa parecer mais trabalhoso no início, os benefícios a longo prazo superam amplamente qualquer esforço adicional.&lt;/p&gt;

&lt;h2&gt;
  
  
  P.S
&lt;/h2&gt;

&lt;p&gt;Na época em que estávamos fazendo essa mudança lá na empresa, o blog &lt;strong&gt;The Pragmatic Engineer&lt;/strong&gt; escreveu um &lt;a href="https://newsletter.pragmaticengineer.com/p/stacked-diffs" rel="noopener noreferrer"&gt;artigo sobre como usar stacked diffs&lt;/a&gt;, que é uma técnica muito boa para escrever PRs pequenos.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>github</category>
      <category>git</category>
    </item>
    <item>
      <title>Setup Rails Active Storage with Hetzner</title>
      <dc:creator>Diogo Viana</dc:creator>
      <pubDate>Fri, 11 Apr 2025 20:07:11 +0000</pubDate>
      <link>https://forem.com/diogoviana19/setup-rails-active-storage-with-hetzner-1mk2</link>
      <guid>https://forem.com/diogoviana19/setup-rails-active-storage-with-hetzner-1mk2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you don't know what &lt;a href="https://www.hetzner.com/de/" rel="noopener noreferrer"&gt;Hetzner&lt;/a&gt; is, you're missing out. It is a cloud provider very similar to Digital Ocean, but with incredibly cheap prices. Currently, it's my first choice when it comes to deploying my side projects.&lt;/p&gt;

&lt;p&gt;While Hetzner doesn't have as many features as Digital Ocean, they have the important ones. And today I'd like to talk about one in particular, the &lt;a href="https://www.hetzner.com/de/" rel="noopener noreferrer"&gt;Object Storage&lt;/a&gt;. It's basically a wrapper for AWS S3 with cheap prices and none of the complexity to set up.&lt;/p&gt;

&lt;p&gt;So, if you want to try &lt;a href="https://guides.rubyonrails.org/active_storage_overview.html" rel="noopener noreferrer"&gt;Rails Active Storage&lt;/a&gt; with Hetzner, I'm going to show you how easy it is to set up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rails 6.0 or higher&lt;/li&gt;
&lt;li&gt;A Hetzner account&lt;/li&gt;
&lt;li&gt;Basic understanding of Rails Active Storage&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Creating a Bucket&lt;/li&gt;
&lt;li&gt;Generating Credentials&lt;/li&gt;
&lt;li&gt;Configuring Your Rails Application&lt;/li&gt;
&lt;li&gt;Testing Your Configuration&lt;/li&gt;
&lt;li&gt;Security Considerations&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating a Bucket
&lt;/h2&gt;

&lt;p&gt;The first thing you have to do is go to your Hetzner account and create a new bucket, by clicking on Object Storage on the sidebar then "Create Bucket" on the right top corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp26n8sngvx7ioy3nt905.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp26n8sngvx7ioy3nt905.png" alt="Hetzner Object Storage dashboard with Create Bucket button highlighted" width="432" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, you'll see this modal asking to select location, input a name &lt;strong&gt;(this will be important)&lt;/strong&gt; for your bucket which will be also used as URL. For object lock, you can leave it as disabled, and in visibility, you can select public (read-only).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswqctzzw3xlhsu127k08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswqctzzw3xlhsu127k08.png" alt="Hetzner bucket creation modal with location, name, and visibility options" width="432" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it, the bucket is ready for you to use it. But before you can set up your app to use it, we need to generate credentials, which is also very easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating Credentials
&lt;/h2&gt;

&lt;p&gt;When you click on your bucket, you'll be redirected to an overview page and in that page, you'll click on "Actions" -&amp;gt; "Generate Credentials". You'll be prompted to input a description for those credentials and that's it. Copy both access key and secret key into a safe place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jmqd4i9rkbguelu55uj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jmqd4i9rkbguelu55uj.png" alt="Hetzner credentials generation interface with access key and secret key displayed" width="439" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Your Rails Application
&lt;/h2&gt;

&lt;p&gt;The first thing to do is to add the gem &lt;a href="https://rubygems.org/gems/aws-sdk-s3" rel="noopener noreferrer"&gt;aws-sdk-s3&lt;/a&gt; that is basic the client that is going to interact with S3 API.&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;# add to your gemfile and then run bundle install&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'aws-sdk-s3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;require: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we need to save those credentials somewhere in the application. You can either use the &lt;a href="https://github.com/bkeepers/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt; gem, which I don't recommend for secrets, or you can use Rails' built-in credentials system.&lt;/p&gt;

&lt;p&gt;I'm going to use Rails' credentials system. Let's use the Rails commands to set the secrets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/rails credentials:edit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save your keys exactly like this:&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="na"&gt;hetzner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;access_key_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;
  &lt;span class="na"&gt;secret_access_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;YOUR_SECRET_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's edit your &lt;code&gt;config/storage.yml&lt;/code&gt; file:&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="na"&gt;hetzner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S3&lt;/span&gt; &lt;span class="c1"&gt;# YES, this is correct! Hetzner is S3 compatible, remember?&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://hel1.your-objectstorage.com&lt;/span&gt; &lt;span class="c1"&gt;# Format: https://&amp;lt;region&amp;gt;.your-objectstorage.com&lt;/span&gt;
  &lt;span class="na"&gt;access_key_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= Rails.application.credentials.dig(:hetzner, :access_key_id) %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;secret_access_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= Rails.application.credentials.dig(:hetzner, :secret_access_key) %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eu-central&lt;/span&gt; &lt;span class="c1"&gt;# if you selected Finland as location&lt;/span&gt;
  &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;the name you gave your bucket when creating it&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The endpoint URL format varies by region. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finland: &lt;code&gt;https://hel1.your-objectstorage.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Germany: &lt;code&gt;https://fsn1.your-objectstorage.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;USA: &lt;code&gt;https://us1.your-objectstorage.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The last part is to change your &lt;strong&gt;config/environments/production.rb&lt;/strong&gt; file to use the new Hetzner configuration you just added:&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;# Store uploaded files on the local file system (see config/storage.yml for options).&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;active_storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:hetzner&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Your Configuration
&lt;/h2&gt;

&lt;p&gt;To verify your configuration is working correctly, you can use the Rails console:&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;# Start the Rails console&lt;/span&gt;
&lt;span class="n"&gt;rails&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;

&lt;span class="c1"&gt;# Test the connection&lt;/span&gt;
&lt;span class="no"&gt;ActiveStorage&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"test.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this returns &lt;code&gt;false&lt;/code&gt; (which is expected for a non-existent file), your connection is working properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;p&gt;When using public buckets, consider the following security measures:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Access Control&lt;/strong&gt;: Even with a public bucket, you can still control access through your application logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Validation&lt;/strong&gt;: Implement strict file type and size validation in your models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiring URLs&lt;/strong&gt;: For sensitive files, consider using expiring URLs instead of public access.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;That's it! Now all your files uploaded using Active Storage will be stored in your Hetzner bucket. This setup provides a cost-effective alternative to AWS S3 while maintaining compatibility with Rails Active Storage.&lt;/p&gt;

&lt;p&gt;For more information, check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.hetzner.com/storage/object-storage/overview/" rel="noopener noreferrer"&gt;Hetzner Object Storage Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://guides.rubyonrails.org/active_storage_overview.html" rel="noopener noreferrer"&gt;Rails Active Storage Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>storage</category>
      <category>hetzner</category>
      <category>s3</category>
    </item>
    <item>
      <title>8 Anos de Alemanha e como isso me mudou</title>
      <dc:creator>Diogo Viana</dc:creator>
      <pubDate>Sun, 23 Mar 2025 13:19:37 +0000</pubDate>
      <link>https://forem.com/diogoviana19/8-anos-de-alemanha-e-como-isso-me-mudou-2e78</link>
      <guid>https://forem.com/diogoviana19/8-anos-de-alemanha-e-como-isso-me-mudou-2e78</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2gs2j3cnq48nf95mh5xw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2gs2j3cnq48nf95mh5xw.jpg" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No dia 20 de fevereiro de 2025, eu e minha esposa completamos 8 anos na Alemanha. Cheguei aqui com apenas 32 anos e agora sou um quarentão. Nossa filha nasceu aqui em 2018 e hoje fala alemão melhor que nós dois. Aliás, até português ela fala melhor que eu.&lt;/p&gt;

&lt;p&gt;Tudo começou em 2016, quando a startup que eu co-fundei faliu. De repente, me vi sem emprego, sem salário e sem saber o que fazer. E isso tudo no meio de um planejamento de casamento.&lt;/p&gt;

&lt;p&gt;Jogando bola com os amigos, notei que um deles não tinha comparecido à nossa peladinha semanal. Então perguntei: "Ué, cadê o Rafael?". A resposta foi simples e direta: "Mudou para a Polônia". Mas como assim? Semana passada ele estava lá jogando com a gente.&lt;/p&gt;

&lt;p&gt;Foi aí que entrei em contato com ele por e-mail e perguntei como isso tinha acontecido. Ele me explicou que já estava há algum tempo participando de processos no exterior através de uma empresa de recrutamento chamada &lt;a href="http://honeypot.io" rel="noopener noreferrer"&gt;honeypot.io&lt;/a&gt; (que foi incorporada pela Xing – um tipo de LinkedIn).&lt;/p&gt;

&lt;p&gt;Como eu não tinha mais emprego, era uma boa hora de mandar meu currículo para qualquer lugar do mundo e tentar morar fora novamente, depois de uma experiência em San Francisco, CA.&lt;/p&gt;

&lt;p&gt;Pois bem, depois de muitos processos, consegui três ofertas oficiais: uma dos EUA (remoto, morando no Brasil), uma em BH e outra para me mudar para a Alemanha. Você já entendeu qual escolhemos, né? Todo o processo de mudança demorou 6 meses e envolveu muita burocracia, mas isso não é papo para agora.&lt;/p&gt;

&lt;p&gt;O choque cultural foi imenso. Era minha primeira vez na Alemanha, aliás, minha primeira vez em solo europeu. E agora consigo listar 5 pontos sobre o que mais mudou em mim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desigualdade como o motor dos problemas sociais:
&lt;/h3&gt;

&lt;p&gt;A Alemanha me mostrou como a desigualdade social é um dos principais fatores por trás de problemas como criminalidade(e segurança pública no geral). Aqui, a distribuição de renda e o acesso a serviços básicos são mais equilibrados, o que resulta em uma sociedade mais segura e estável. Isso me fez refletir sobre como políticas públicas podem impactar diretamente a qualidade de vida das pessoas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cultura é construção:
&lt;/h3&gt;

&lt;p&gt;Aprendi que a cultura não é algo fixo, mas sim algo que se constrói e se transforma. É comun ver homens(principalmente árabes), demonstrando afeto entre si, algo que no Brasil ainda é visto com certos preconceitos. Isso me mostrou como os valores sociais podem ser diferentes e como é importante respeitar e entender essas diferenças. Ah, e o alemão faz xixi sentado, outro ponto que na nossa cultura não é comum.&lt;/p&gt;

&lt;h3&gt;
  
  
  Não existe lugar perfeito:
&lt;/h3&gt;

&lt;p&gt;A vida na Europa não é um mar de rosas. Apesar das muitas vantagens, também existe muito racismo, xenofobia e preconceitos(nunca sofremos,mas existe) em geral. Isso me fez perceber que quando você muda, você só troca de problemas. Nenhum lugar é perfeito.&lt;/p&gt;

&lt;h3&gt;
  
  
  Menos consumismo, mais foco em experiências:
&lt;/h3&gt;

&lt;p&gt;Aqui, percebi que as pessoas valorizam menos o ter e mais o viver. O consumismo desenfreado que vemos no Brasil dá lugar a um estilo de vida mais simples e focado em experiências, como viagens, passeios e momentos em família. Isso mudou minha perspectiva sobre o que realmente importa na vida.&lt;/p&gt;

&lt;h3&gt;
  
  
  Valorizar mais o Brasil:
&lt;/h3&gt;

&lt;p&gt;Morar fora me fez valorizar ainda mais o Brasil, especialmente o clima e o sol. A Alemanha tem invernos longos e escuros, e isso me fez sentir falta do calor e da luz do Brasil. Além disso, passei a admirar mais a cultura brasileira, nossa diversidade e nossa capacidade de superar desafios. Quando chega um Brasileiro aqui falando mal do Brasil eu já corto e tento mostrar o lado bom.&lt;/p&gt;

&lt;p&gt;-- &lt;br&gt;
Pra finalizar, acho que todo mundo que tiver condição, deveria morar fora(seja do país ou apenas de seu estado). Conhecer novas culturas expande sua cabeça para outros estilos de vida, te ajuda a ser mais empático e acolhedor. Nada mata melhor o preconceito do que conviver com o diferente.&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>alemanha</category>
    </item>
    <item>
      <title>My First Side Project Was a Success—and Then I Blew It</title>
      <dc:creator>Diogo Viana</dc:creator>
      <pubDate>Tue, 10 Dec 2024 00:44:55 +0000</pubDate>
      <link>https://forem.com/diogoviana19/my-first-side-project-was-a-success-and-then-i-blew-it-3kja</link>
      <guid>https://forem.com/diogoviana19/my-first-side-project-was-a-success-and-then-i-blew-it-3kja</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqz4fusujjf1dgvj8q0s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqz4fusujjf1dgvj8q0s.jpg" alt="Image description" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The year was 2005, and I was in my second year of Computer Science. I loved web development and wanted to learn a language that could help me build real applications.&lt;/p&gt;

&lt;p&gt;At the time, tabletop RPG players—myself included—had a problem. Games like &lt;em&gt;Vampire: The Masquerade&lt;/em&gt; required groups to meet in person, but as we grew older, got jobs, and scattered across cities, gathering became impossible. There were no online tools to play RPGs with friends.&lt;/p&gt;

&lt;p&gt;So I decided to build one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Birth of a (Very Messy) Solution
&lt;/h3&gt;

&lt;p&gt;I bought a PHP book and dove in. But I quickly realized: Programming isn't learned by reading alone—you have to &lt;em&gt;build&lt;/em&gt;. So I set out to create a platform where game masters could form groups, manage players, and run sessions with a chat and dice-rolling system.&lt;/p&gt;

&lt;p&gt;This was 2005:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No YouTube tutorials(actually, no Youtube at all)&lt;/li&gt;
&lt;li&gt;No Stack Overflow&lt;/li&gt;
&lt;li&gt;Just Orkut forums&lt;/li&gt;
&lt;li&gt;A dog-eared PHP manual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Somehow, I made it work. The code was spaghetti, the frontend used HTML tables for layout (CSS was a mystery), and deployment meant FTP-ing files via FileZilla. But it &lt;em&gt;worked&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Rise and Fall of My RPG Empire
&lt;/h3&gt;

&lt;p&gt;I announced the tool on Orkut's RPG communities. Players went wild:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 users in two weeks&lt;/li&gt;
&lt;li&gt;7,000 visitors that month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was euphoric, dreaming of new features.&lt;/p&gt;

&lt;p&gt;Then reality hit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No version control (GitHub didn't exist)&lt;/li&gt;
&lt;li&gt;My "deployment strategy": Take site offline to code updates&lt;/li&gt;
&lt;li&gt;Sent the fateful email: "We'll be back with upgrades!"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was so naive that I thought "I have to take the web app down while I write new features, and then when it's finished, I'll put it back up." - I didn't know version control, remember?&lt;/p&gt;

&lt;p&gt;Between my day job and inexperience, I never wrote those features. Years passed. I kept paying for the domain... until 2015, when I finally let go.&lt;/p&gt;

&lt;h3&gt;
  
  
  What did I learn from that?
&lt;/h3&gt;

&lt;p&gt;The most important: Programming is about practice. You're only going to get good at it if you practice. Learn the theory, but practice more. Write code. Read code. Try. Fail. Practice every day.&lt;/p&gt;

&lt;p&gt;Do not let yourself down if things don't work out as you expected. Just build. Eventually, you'll get it right and learn a ton along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  PS.
&lt;/h3&gt;

&lt;p&gt;Two decades later, I'm finally building again. Not for glory, but for the joy of creating—and this time they made it to production.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://frame6.me/" rel="noopener noreferrer"&gt;Frame6&lt;/a&gt; - A game quiz about movies. You can play alone or with your friends.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://passshare.me/" rel="noopener noreferrer"&gt;Passshare&lt;/a&gt; - A web application for sharing passwords in a secure way.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>braziliandevs</category>
      <category>indiehacker</category>
      <category>indiehacking</category>
    </item>
    <item>
      <title>Docker Compose with Rails 8, Tailwind and SQLite</title>
      <dc:creator>Diogo Viana</dc:creator>
      <pubDate>Mon, 18 Nov 2024 22:03:11 +0000</pubDate>
      <link>https://forem.com/diogoviana19/docker-compose-with-rails-8-tailwind-and-sqlite-1k3m</link>
      <guid>https://forem.com/diogoviana19/docker-compose-with-rails-8-tailwind-and-sqlite-1k3m</guid>
      <description>&lt;p&gt;Hello, long time no see!&lt;/p&gt;

&lt;p&gt;In this guide I'm going to show you how to use Docker Compose to setup and run a Ruby On Rails application using the brand new version 8. In this guide I'm not going to list all new features that are shipped with the newest version. If you want to know more about, you can check the &lt;a href="https://rubyonrails.org/2024/9/27/rails-8-beta1-no-paas-required" rel="noopener noreferrer"&gt;official release note&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There's only one requirement to make this guide work, which is having &lt;a href="https://www.docker.com/products/docker-desktop/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; or &lt;a href="https://orbstack.dev/download" rel="noopener noreferrer"&gt;OrbStack&lt;/a&gt; installed on your computer. That's it. You don't need to install Ruby, Postgres, SQLite, Redis... nothing.&lt;/p&gt;

&lt;p&gt;This is an updated version of a &lt;a href="https://github.com/dviana19/awesome-docker-rails?tab=readme-ov-file" rel="noopener noreferrer"&gt;quickstart guide&lt;/a&gt; I wrote a while back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup folder
&lt;/h3&gt;

&lt;p&gt;First, let's create a directory for your project and then create 5 empty files inside of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-project
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
&lt;span class="nb"&gt;touch &lt;/span&gt;Dockerfile.dev
&lt;span class="nb"&gt;touch &lt;/span&gt;docker-compose.yml
&lt;span class="nb"&gt;touch &lt;/span&gt;Gemfile
&lt;span class="nb"&gt;touch &lt;/span&gt;Gemfile.lock
&lt;span class="nb"&gt;touch&lt;/span&gt; .ruby-version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define the project
&lt;/h3&gt;

&lt;p&gt;Start by setting up the files needed to build the app. The app will run inside a Docker container containing its dependencies. Defining dependencies is done using a file called &lt;code&gt;Dockerfile.dev&lt;/code&gt;. Let's add the following inside of it::&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# syntax = docker/dockerfile:1&lt;/span&gt;

&lt;span class="c"&gt;# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; RUBY_VERSION=3.4.2&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; registry.docker.com/library/ruby:$RUBY_VERSION-slim-bookworm&lt;/span&gt;

&lt;span class="c"&gt;# Rails app lives here&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /rails&lt;/span&gt;

&lt;span class="c"&gt;# Install packages needed to build gems&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="nt"&gt;-qq&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; build-essential git libpq-dev libvips pkg-config node-gyp curl sqlite3 nano libyaml-dev

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; NODE_VERSION=20.15.0&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; YARN_VERSION=latest&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH=/usr/local/node/bin:$PATH&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://github.com/nodenv/node-build/archive/master.tar.gz | &lt;span class="nb"&gt;tar &lt;/span&gt;xz &lt;span class="nt"&gt;-C&lt;/span&gt; /tmp/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  /tmp/node-build-master/bin/node-build &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; /usr/local/node &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; yarn@&lt;span class="nv"&gt;$YARN_VERSION&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /tmp/node-build-master

&lt;span class="c"&gt;# Run bundle install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Gemfile Gemfile.lock ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; .ruby-version ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Copy application code&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Entrypoint prepares the database.&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/rails/bin/docker-entrypoint"]&lt;/span&gt;

&lt;span class="c"&gt;# Start the server by default, this can be overwritten at runtime&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["rails", "server", "-b", "0.0.0.0"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is important to use the .dev as extension for this file otherwise rails new command will replace it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That'll put your application code inside an image that builds a container&lt;br&gt;
with Ruby, Bundler and all your dependencies inside it. For more information on&lt;br&gt;
how to write Dockerfiles, see the &lt;a href="https://docs.docker.com/get-started/" rel="noopener noreferrer"&gt;Docker user guide&lt;/a&gt;&lt;br&gt;
and the &lt;a href="https://docs.docker.com/engine/reference/builder/" rel="noopener noreferrer"&gt;Dockerfile reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, open an editor and create a bootstrap &lt;code&gt;Gemfile&lt;/code&gt; which just loads Rails. This will be overwritten in a moment by &lt;code&gt;rails new&lt;/code&gt;. At this point you can use whatever rails version you want.&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;source&lt;/span&gt; &lt;span class="s1"&gt;'https://rubygems.org'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 8.0'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To have all files using the same version, let's add this to the .ruby-version file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ruby-3.4.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, &lt;code&gt;docker-compose.yml&lt;/code&gt; is where the magic happens. This file describes the services that comprise your app and the configuration needed to make the app run.&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="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile.dev&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash -c "./bin/dev"&lt;/span&gt;
    &lt;span class="na"&gt;tty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/rails&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You have to use tty:true so we can watch for changes on css/js files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Build the project
&lt;/h3&gt;

&lt;p&gt;With those files in place, you can now generate the Rails skeleton app using &lt;a href="https://docs.docker.com/engine/reference/commandline/compose_run/" rel="noopener noreferrer"&gt;docker compose run&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker compose run &lt;span class="nt"&gt;--no-deps&lt;/span&gt; web rails new &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-project  &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--css&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tailwind &lt;span class="nt"&gt;--js&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;esbuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run this command, Compose builds the image for the &lt;code&gt;web&lt;/code&gt; service using the &lt;code&gt;Dockerfile.dev&lt;/code&gt; file.&lt;br&gt;
The &lt;code&gt;--no-deps&lt;/code&gt; tells Compose not to start linked services. Then it runs &lt;code&gt;rails new&lt;/code&gt; inside a new container, using that image.&lt;/p&gt;

&lt;p&gt;Once it's done, you should have generated a fresh app inside of your folder.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are running Docker on Linux, the files &lt;code&gt;rails new&lt;/code&gt; created are owned by root, you might have to run chown to change that.&lt;/p&gt;


&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$USER&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Now that you’ve got a new Gemfile, you need to build the image again. (This, and changes to the &lt;code&gt;Gemfile&lt;/code&gt; or the Dockerfile, should be the only times you’ll need to rebuild.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker compose build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the project
&lt;/h3&gt;

&lt;p&gt;Before you boot your app, let's make sure we bind 0.0.0.0 to our server. Go to &lt;code&gt;Procfile.dev&lt;/code&gt; and add '-b 0.0.0.0' at the end of the first line, it should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;web: env RUBY_DEBUG_OPEN=true bin/rails server -b 0.0.0.0
js: yarn build --watch
css: yarn build:css --watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the last step before you spin your project app, let's do some minor modifications on the &lt;code&gt;Dockerfile.dev&lt;/code&gt; file. Add these lines right after&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;COPY ..&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Entrypoint prepares the database.&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/rails/bin/docker-entrypoint"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final Dockerfile.dev should looke like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# syntax = docker/dockerfile:1&lt;/span&gt;

&lt;span class="c"&gt;# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; RUBY_VERSION=3.4.2&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; registry.docker.com/library/ruby:$RUBY_VERSION-slim-bookworm&lt;/span&gt;

&lt;span class="c"&gt;# Rails app lives here&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /rails&lt;/span&gt;

&lt;span class="c"&gt;# Install packages needed to build gems&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="nt"&gt;-qq&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; build-essential git libpq-dev libvips pkg-config node-gyp curl sqlite3 nano libyaml-dev

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; NODE_VERSION=20.15.0&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; YARN_VERSION=latest&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH=/usr/local/node/bin:$PATH&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://github.com/nodenv/node-build/archive/master.tar.gz | &lt;span class="nb"&gt;tar &lt;/span&gt;xz &lt;span class="nt"&gt;-C&lt;/span&gt; /tmp/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  /tmp/node-build-master/bin/node-build &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; /usr/local/node &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; yarn@&lt;span class="nv"&gt;$YARN_VERSION&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /tmp/node-build-master

&lt;span class="c"&gt;# Run bundle install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Gemfile Gemfile.lock ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; .ruby-version ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Copy application code&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Entrypoint prepares the database.&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/rails/bin/docker-entrypoint"]&lt;/span&gt;

&lt;span class="c"&gt;# Start the server by default, this can be overwritten at runtime&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["rails", "server", "-b", "0.0.0.0"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;docker compose build&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 again and then finaly,&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;docker compose up&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
.&lt;/p&gt;
&lt;h3&gt;
  
  
  View the Rails welcome page!
&lt;/h3&gt;

&lt;p&gt;That's it. Your app should now be running on port 3000 on your Docker daemon, go to &lt;code&gt;http://localhost:3000&lt;/code&gt; on a web browser to see the Rails Welcome.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stop the application
&lt;/h3&gt;

&lt;p&gt;To stop the application, run &lt;a href="https://docs.docker.com/engine/reference/commandline/compose_down/" rel="noopener noreferrer"&gt;docker compose down&lt;/a&gt; in your project directory. You can use the same terminal window in which you started the database, or another one where you have access to a command prompt. This is a clean way to stop the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker compose down
 ✔ Container my-project-web-1  Removed0.0s
 ✔ Network my-project_default  Removed
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Restart the application
&lt;/h3&gt;

&lt;p&gt;To restart the application run &lt;code&gt;docker compose up&lt;/code&gt; in the project directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rebuild the application
&lt;/h3&gt;

&lt;p&gt;If you make changes to the Gemfile or the Compose file to try out some different&lt;br&gt;
configurations, you need to rebuild. Some changes require only&lt;br&gt;
&lt;code&gt;docker compose up --build&lt;/code&gt;, but a full rebuild requires a re-run of&lt;br&gt;
&lt;code&gt;docker compose run web bundle install&lt;/code&gt; to sync changes in the &lt;code&gt;Gemfile.lock&lt;/code&gt; to&lt;br&gt;
the host, followed by &lt;code&gt;docker compose up --build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example of the first case, where a full rebuild is not necessary.&lt;br&gt;
Suppose you simply want to change the exposed port on the local host from &lt;code&gt;3000&lt;/code&gt;&lt;br&gt;
in our first example to &lt;code&gt;3001&lt;/code&gt;. Make the change to the Compose file to expose&lt;br&gt;
port &lt;code&gt;3000&lt;/code&gt; on the container through a new port, &lt;code&gt;3001&lt;/code&gt;, on the host, and save&lt;br&gt;
the changes:&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="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3001:3000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, rebuild and restart the app with &lt;code&gt;docker compose up --build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside the container, your app is running on the same port as before &lt;code&gt;3000&lt;/code&gt;, but&lt;br&gt;
the Rails Welcome is now available on &lt;code&gt;http://localhost:3001&lt;/code&gt; on your local&lt;br&gt;
host.&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>rails</category>
      <category>sqlite</category>
      <category>docker</category>
    </item>
    <item>
      <title>Good alternatives to Heroku</title>
      <dc:creator>Diogo Viana</dc:creator>
      <pubDate>Sun, 26 May 2024 00:23:29 +0000</pubDate>
      <link>https://forem.com/diogoviana19/good-alternatives-to-heroku-4ach</link>
      <guid>https://forem.com/diogoviana19/good-alternatives-to-heroku-4ach</guid>
      <description>&lt;p&gt;A while ago, I attempted to deploy a side project on Heroku, and, to my surprise, a lot had changed on the platform. Basically, Heroku's free-tier service was no longer available. This was not only bad news for me, but also for every Rails developer who had side projects running there.&lt;/p&gt;

&lt;p&gt;So, I went to Twitter to express my concerns about these changes and received many replies suggesting good alternatives. As a result, I have compiled all these suggestions here for you and for my future reference&lt;/p&gt;

&lt;h4&gt;
  
  
  Here's the list:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.digitalocean.com/" rel="noopener noreferrer"&gt;Digital Ocean&lt;/a&gt; -&lt;br&gt;
Good prices, documentation and they have something similar to Heroku with App Platform. Good for small and big projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.hetzner.com/de/" rel="noopener noreferrer"&gt;Hetzner&lt;/a&gt; -&lt;br&gt;
Very similar to Digital Ocean, you can create VPS, databases, load balancers and more. Good prices and it can handle both big and small projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; -&lt;br&gt;
Never used but and it seems very specific for Frontend developers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://fly.io/" rel="noopener noreferrer"&gt;Fly.io&lt;/a&gt; -&lt;br&gt;
Very similar to Heroku too, easy to use and support for multiple stacks/languages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pocketbase.io/" rel="noopener noreferrer"&gt;Pocketbase&lt;/a&gt; -&lt;br&gt;
Never used before but it says in their home page the following: "Open Source backend for your next SaaS and Mobile app in 1 file". Seems porwerful.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://planetscale.com" rel="noopener noreferrer"&gt;Planetscale&lt;/a&gt; -&lt;br&gt;
Directly from their website: "PlanetScale is a MySQL-compatible serverless database that brings you scale, performance, and reliability — without sacrificing developer experience."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://render.com/" rel="noopener noreferrer"&gt;Render&lt;/a&gt; -&lt;br&gt;
I think render is more like a cloud agnostic builder/runner platform, this means that your application needs to be hosted somewhere else.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://railway.app/" rel="noopener noreferrer"&gt;Railway&lt;/a&gt; -&lt;br&gt;
Language agnostic and for projects big and small. Never used but it seems very easy to use like Heroku.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Subpabase&lt;/a&gt; -&lt;br&gt;
Like Planetscale this is only for databases. It is an open source Firebase alternative for building secure and performant Postgres backends with minimal configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.oracle.com/cloud/free/" rel="noopener noreferrer"&gt;Oracle Cloud&lt;/a&gt; -&lt;br&gt;
Oracle Cloud offers a free-tier for a year.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.amplify.aws/" rel="noopener noreferrer"&gt;AWS Amplify&lt;/a&gt; -&lt;br&gt;
Very easy to use, connects to your github repository and can also create review apps based on branches.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.cyclic.sh/" rel="noopener noreferrer"&gt;Cyclic&lt;/a&gt; -&lt;br&gt;
"Connect your GitHub repo. We will build, deploy and manage the hosting."&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And last but not least, &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, which is the one I use to host this website(for free). &lt;a href="https://gohugo.io/" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt; + Netlify is a powerful combination.&lt;/p&gt;

&lt;p&gt;If you have any suggestions that I might have missed, feel free to post in the comments.&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>heroku</category>
      <category>rails</category>
    </item>
  </channel>
</rss>
