<?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: Shah Zaib</title>
    <description>The latest articles on DEV Community by Shah Zaib (@shahzaib).</description>
    <link>https://dev.to/shahzaib</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%2F276769%2F25797987-4cd8-4744-857e-d72007e6ae95.png</url>
      <title>DEV Community: Shah Zaib</title>
      <link>https://dev.to/shahzaib</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shahzaib"/>
    <language>en</language>
    <item>
      <title>Handling Errors and Job Lifecycles in Rails 7.1: Master ActiveJob with `retry_on`, `discard_on`, and `after_discard`</title>
      <dc:creator>Shah Zaib</dc:creator>
      <pubDate>Tue, 05 Nov 2024 00:44:12 +0000</pubDate>
      <link>https://dev.to/shahzaib/handling-errors-and-job-lifecycles-in-rails-71-master-activejob-with-retryon-discardon-and-afterdiscard-5b4b</link>
      <guid>https://dev.to/shahzaib/handling-errors-and-job-lifecycles-in-rails-71-master-activejob-with-retryon-discardon-and-afterdiscard-5b4b</guid>
      <description>&lt;p&gt;Ruby on Rails 7.1 introduces some pivotal features to ActiveJob, streamlining error handling and job lifecycle management. In this post, I’ll walk you through how to effectively use &lt;code&gt;after_discard&lt;/code&gt;, &lt;code&gt;discard_on&lt;/code&gt;, and &lt;code&gt;retry_on&lt;/code&gt; with examples to make your background job handling more robust.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. &lt;code&gt;after_discard&lt;/code&gt; Hook: Custom Actions for Discarded Jobs
&lt;/h2&gt;

&lt;p&gt;Rails 7.1 introduces the &lt;code&gt;after_discard&lt;/code&gt; callback, which lets you run custom logic when a job is discarded. It’s handy for logging errors, notifying administrators, or cleaning up resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&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;MyJob&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationJob&lt;/span&gt;
  &lt;span class="n"&gt;discard_on&lt;/span&gt; &lt;span class="no"&gt;CustomError&lt;/span&gt;

  &lt;span class="n"&gt;after_discard&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;job&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="s2"&gt;"Job &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;job_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was discarded."&lt;/span&gt;
    &lt;span class="c1"&gt;# You can add custom actions here, like sending notifications&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;perform&lt;/span&gt;
    &lt;span class="c1"&gt;# Your job logic that might raise a CustomError&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;In this example, if &lt;code&gt;CustomError&lt;/code&gt; occurs, the job gets discarded. The &lt;code&gt;after_discard&lt;/code&gt; hook then logs the event and can trigger any additional custom behavior you need.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. &lt;code&gt;discard_on&lt;/code&gt;: Efficient Handling of Irrecoverable Errors
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;discard_on&lt;/code&gt; to specify exceptions that should result in discarding the job instead of retrying. This is crucial for errors you know cannot be fixed by retrying, like invalid data or a permanently missing record.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&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;ExampleJob&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationJob&lt;/span&gt;
  &lt;span class="n"&gt;discard_on&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RecordNotFound&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyModel&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;record_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Raises an error if the record isn’t found&lt;/span&gt;
    &lt;span class="c1"&gt;# Perform your job logic on the record&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;When &lt;code&gt;ActiveRecord::RecordNotFound&lt;/code&gt; is raised in this job, it is gracefully discarded without consuming additional resources or retries.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. &lt;code&gt;retry_on&lt;/code&gt;: Automatic Retries for Recoverable Errors
&lt;/h2&gt;

&lt;p&gt;For errors that are likely temporary, &lt;code&gt;retry_on&lt;/code&gt; provides a way to automatically retry jobs with configurable delays and limits. This is perfect for handling issues like network timeouts or transient service failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example:
&lt;/h3&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;RetryJob&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationJob&lt;/span&gt;
  &lt;span class="n"&gt;retry_on&lt;/span&gt; &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;OpenTimeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;wait: &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;attempts: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform&lt;/span&gt;
    &lt;span class="c1"&gt;# Job logic that might encounter a temporary network issue&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;Here, if a &lt;code&gt;Net::OpenTimeout&lt;/code&gt; error occurs, the job will retry up to three times with a 5-second pause between attempts, giving the external service a chance to recover.&lt;/p&gt;




&lt;h2&gt;
  
  
  Need a Rails Expert?
&lt;/h2&gt;

&lt;p&gt;If you love what Rails can do and need a skilled full-stack developer to help you build robust, high-performance web applications, I'm available for new opportunities! &lt;/p&gt;

&lt;h3&gt;
  
  
  About Me: Shah Zaib
&lt;/h3&gt;

&lt;p&gt;I’m a Full-Stack Developer and Technologist with 10+ years of experience delivering exceptional web projects. My expertise includes Ruby on Rails, Hotwire, and AI-powered solutions. From real-time app experiences to seamless AI integration, I’m passionate about transforming concepts into impactful software.&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://www.linkedin.com/in/shahzaibfullstack/" rel="noopener noreferrer"&gt;Connect with me on LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s discuss how I can help you innovate and elevate your next project!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>activitypub</category>
      <category>webdev</category>
    </item>
    <item>
      <title>🚨 New Rails Versions Released: Addressing ReDoS Vulnerabilities 🚨</title>
      <dc:creator>Shah Zaib</dc:creator>
      <pubDate>Wed, 16 Oct 2024 00:24:59 +0000</pubDate>
      <link>https://dev.to/shahzaib/new-rails-versions-released-addressing-redos-vulnerabilities-28o9</link>
      <guid>https://dev.to/shahzaib/new-rails-versions-released-addressing-redos-vulnerabilities-28o9</guid>
      <description>&lt;p&gt;The Rails community has recently released &lt;strong&gt;Rails versions 6.1.7.9, 7.0.8.5, 7.1.4.1, and 7.2.1.1&lt;/strong&gt;, addressing critical &lt;strong&gt;ReDoS (Regular Expression Denial of Service)&lt;/strong&gt; vulnerabilities. If you are using Ruby 3.1 or earlier versions, it's crucial to upgrade to mitigate these security risks.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚨 Key Issues Resolved:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CVE-2024-47887&lt;/strong&gt; - Possible ReDoS vulnerability in HTTP Token authentication within Action Controller.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CVE-2024-41128&lt;/strong&gt; - Possible ReDoS vulnerability in query parameter filtering in Action Dispatch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CVE-2024-47888&lt;/strong&gt; - Possible ReDoS vulnerability in &lt;code&gt;plain_text_for_blockquote_node&lt;/code&gt; within Action Text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CVE-2024-47889&lt;/strong&gt; - Possible ReDoS vulnerability in &lt;code&gt;block_format&lt;/code&gt; within Action Mailer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  💡 Why Should You Upgrade?
&lt;/h3&gt;

&lt;p&gt;Ruby 3.1 is approaching &lt;strong&gt;end of life for security support&lt;/strong&gt;, which means these vulnerabilities specifically affect applications running on &lt;strong&gt;Ruby versions below 3.2&lt;/strong&gt;. By upgrading your Rails version, you're not only patching critical vulnerabilities but also ensuring your application remains secure and optimized for performance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rails &lt;strong&gt;8.0.0.beta1&lt;/strong&gt; and newer releases are &lt;strong&gt;unaffected&lt;/strong&gt; by these issues since they require Ruby 3.2+.&lt;/li&gt;
&lt;li&gt;Many developers still use older Rails versions that may be vulnerable—upgrading to the latest releases ensures you have vital security coverage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📈 What Does This Mean for Your Application?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Risk for Older Ruby Versions&lt;/strong&gt;: If you're still on &lt;strong&gt;Ruby 3.1&lt;/strong&gt;, it's time to upgrade to &lt;strong&gt;Ruby 3.2 or higher&lt;/strong&gt;. Ruby 3.2 provides stronger protections against ReDoS attacks and improves overall security.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extended Maintenance for Rails 6.1&lt;/strong&gt;: The Rails team has extended support for &lt;strong&gt;Rails 6.1&lt;/strong&gt; by releasing &lt;strong&gt;6.1.7.9&lt;/strong&gt;, despite earlier plans to end maintenance. This extension gives teams running older versions time to transition smoothly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Rails 6.1.7.9 and newer versions provide critical patches and help you secure your application from ReDoS vulnerabilities. Don't delay upgrading!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  🚀 What Should You Do Next?
&lt;/h3&gt;

&lt;p&gt;If your application is running on &lt;strong&gt;Ruby 3.1&lt;/strong&gt; or an earlier Rails version, now is the time to upgrade to the latest Rails releases to protect your application from these vulnerabilities. Ensuring that your application is updated guarantees better security and performance in the long term.&lt;/p&gt;

&lt;p&gt;Need assistance with your upgrade process? I'm here to help! Let's work together to get your applications running on the latest Rails versions, keeping them safe and high-performing.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>redos</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Unlocking the Power of Ruby on Rails 8: What Developers Need to Know</title>
      <dc:creator>Shah Zaib</dc:creator>
      <pubDate>Tue, 08 Oct 2024 10:08:12 +0000</pubDate>
      <link>https://dev.to/shahzaib/unlocking-the-power-of-ruby-on-rails-8-what-developers-need-to-know-275d</link>
      <guid>https://dev.to/shahzaib/unlocking-the-power-of-ruby-on-rails-8-what-developers-need-to-know-275d</guid>
      <description>&lt;p&gt;Ruby on Rails has always been a game-changer in web development. With &lt;strong&gt;Rails 8&lt;/strong&gt; on the horizon, it's set to push the boundaries even further. Whether you're a seasoned developer or just starting out, Rails 8 offers improvements that will streamline your work and make your apps more efficient. Let’s dive into the standout features that will redefine how you build web applications. 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;strong&gt;Turbo 2.0 for Seamless Interactivity&lt;/strong&gt; ⚡
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Turbo 2.0&lt;/strong&gt; elevates the Turbo framework, making it easier to build dynamic, interactive applications without writing extensive JavaScript. Form submissions now update HTML without reloading the page—no custom AJAX scripts required.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; Cleaner codebase, enhanced user experience, and faster development.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. &lt;strong&gt;Effortless Deployments with Kamal 2 and Thruster&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Deploying apps is smoother than ever with &lt;strong&gt;Kamal 2&lt;/strong&gt;. Whether you're using cloud VMs or in-house servers, Kamal 2 simplifies deployment, while &lt;strong&gt;Thruster&lt;/strong&gt; adds asset caching and HTTP/2 support, ensuring zero-downtime deployments.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; No need for external services like Nginx or PaaS, reducing costs and boosting efficiency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. &lt;strong&gt;Solid Cache, Solid Queue, and Solid Cable: Redis Alternatives&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Rails 8 introduces &lt;strong&gt;Solid Cache&lt;/strong&gt;, &lt;strong&gt;Solid Queue&lt;/strong&gt;, and &lt;strong&gt;Solid Cable&lt;/strong&gt;—tools that replace dependencies like Redis or Memcached. Built on SQLite, they simplify caching, job queues, and WebSocket functionality.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; Reduced third-party dependencies and simplified infrastructure management.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. &lt;strong&gt;SQLite Ready for Production&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;SQLite is no longer just for development or small projects. &lt;strong&gt;Rails 8&lt;/strong&gt; optimizes SQLite for production, allowing companies like 37signals to successfully deploy it in real-world applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; No need for complex databases like PostgreSQL or MySQL for smaller projects. SQLite can handle serious production loads now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. &lt;strong&gt;Propshaft: The New Asset Pipeline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Say goodbye to Sprockets! &lt;strong&gt;Propshaft&lt;/strong&gt; is now the default asset pipeline, designed for modern web development. It integrates seamlessly with tools like Esbuild and Vite.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; Faster, more efficient asset management with support for modern development tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. &lt;strong&gt;Built-In Authentication System&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Rails 8 introduces a fully integrated authentication system. By running &lt;code&gt;rails g authentication&lt;/code&gt;, you get a session-based authentication system with password reset functionality.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; No need to integrate third-party authentication solutions, saving time and reducing complexity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  7. &lt;strong&gt;New Script Folder and Generator&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Rails 8 introduces a new &lt;strong&gt;script folder&lt;/strong&gt; to organize one-off scripts like data migrations or cleanups, making it easier to maintain your codebase.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; Improved organization, leading to cleaner, more maintainable projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  8. &lt;strong&gt;Active Record Enhancements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Rails 8 brings major improvements to &lt;strong&gt;Active Record&lt;/strong&gt;, including support for PostgreSQL table inheritance, reversible schema operations, and faster data seeding with bulk insert fixtures.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; Faster, more reliable database operations for large-scale applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  9. &lt;strong&gt;Simplified Job Handling with Solid Queue&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Solid Queue&lt;/strong&gt; replaces the need for Redis or Sidekiq, using SQLite or PostgreSQL/MySQL for background job handling. This built-in feature makes job processing more efficient and less reliant on external services.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; Simplifies background job processing, reducing infrastructure complexity and cost.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  10. &lt;strong&gt;PostgreSQL and MySQL Improvements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Rails 8 also brings enhancements for PostgreSQL and MySQL, including better support for float types in PostgreSQL and datetime precision in MySQL.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why It Matters:&lt;/strong&gt; Working with complex databases just got a lot easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Rails 8&lt;/strong&gt; isn’t just an upgrade; it’s a revolution. From &lt;strong&gt;Kamal 2&lt;/strong&gt; for deployments to &lt;strong&gt;Solid Cache&lt;/strong&gt; for streamlined infrastructure, Rails 8 is packed with features that make web development easier, faster, and more scalable. Now is the time to explore everything this new version has to offer!&lt;/p&gt;

&lt;h1&gt;
  
  
  RubyOnRails #Rails8 #WebDevelopment #Turbo2 #SQLite #SolidCache #Propshaft #Deployment #ActiveRecord #BuiltInAuth #FullStackDevelopment
&lt;/h1&gt;

</description>
      <category>rails</category>
      <category>docker</category>
      <category>devops</category>
      <category>deployment</category>
    </item>
    <item>
      <title>Effortless Rails 7+ Deployment with Kamal Gem on DigitalOcean</title>
      <dc:creator>Shah Zaib</dc:creator>
      <pubDate>Tue, 30 Jul 2024 17:55:18 +0000</pubDate>
      <link>https://dev.to/shahzaib/effortless-rails-7-deployment-with-kamal-gem-on-digitalocean-of</link>
      <guid>https://dev.to/shahzaib/effortless-rails-7-deployment-with-kamal-gem-on-digitalocean-of</guid>
      <description>&lt;p&gt;Deploying a Rails application can often be daunting, especially when aiming for a production-ready setup. This guide will walk you through deploying a Rails 7.1+ application using the Kamal gem on Digital Ocean. By the end of this post, you'll have your app live and running with minimal hassle.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Basic knowledge of Ruby on Rails&lt;/li&gt;
&lt;li&gt;A Rails 7.1+ application&lt;/li&gt;
&lt;li&gt;A Digital Ocean account&lt;/li&gt;
&lt;li&gt;Docker installed on your local machine&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Install Kamal Gem
&lt;/h2&gt;

&lt;p&gt;First, let's install the Kamal gem. Add the gem to your Gemfile and run the bundle 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 add kamal &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Initialize Kamal Configuration
&lt;/h2&gt;

&lt;p&gt;Initialize Kamal configuration 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;kamal init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will generate two crucial files: &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;config/deploy.yml&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Configure .env File
&lt;/h2&gt;

&lt;p&gt;Add the following environment variables to your &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RAILS_MASTER_KEY=XXXXXXXXXX
KAMAL_REGISTRY_PASSWORD=XXXXXXXXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;RAILS_MASTER_KEY&lt;/code&gt;: Your Rails master key.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KAMAL_REGISTRY_PASSWORD&lt;/code&gt;: Your Docker Registry password. To find it, go to &lt;a href="https://hub.docker.com" rel="noopener noreferrer"&gt;hub.docker.com&lt;/a&gt;, log in, and create a new token under Account Settings &amp;gt; Security &amp;gt; New Access Token.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Update deploy.yml
&lt;/h2&gt;

&lt;p&gt;Purchase a VPS from Digital Ocean and add its IP to the relevant field in &lt;code&gt;deploy.yml&lt;/code&gt;. Update the configuration according to your project credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example &lt;code&gt;config/deploy.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Name of your application. Used to uniquely configure containers.&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;myapp&lt;/span&gt;

&lt;span class="c1"&gt;# Docker image&lt;/span&gt;
&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;username/myapp&lt;/span&gt;

&lt;span class="c1"&gt;# Main server configuration&lt;/span&gt;
&lt;span class="na"&gt;servers&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;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;traefik.http.routers.messi-web.rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Host(`intellecta.app`)&lt;/span&gt;
      &lt;span class="na"&gt;traefik.http.routers.messi-web.tls&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;traefik.http.routers.messi-web.entrypoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;websecure&lt;/span&gt;
      &lt;span class="na"&gt;traefik.http.routers.messi-web.tls.certresolver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt&lt;/span&gt;

  &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;cmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bundle exec sidekiq -q high_priority -q default -q mailers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Registry Configuration
&lt;/h2&gt;

&lt;p&gt;Configure your Docker registry credentials in &lt;code&gt;deploy.yml&lt;/code&gt;:&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="c1"&gt;# Credentials for your image host.&lt;/span&gt;
&lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Specify the registry server if you're not using Docker Hub&lt;/span&gt;
  &lt;span class="c1"&gt;# server: registry.digitalocean.com / ghcr.io / ...&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shahzaib&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;KAMAL_REGISTRY_PASSWORD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Set Environment Variables
&lt;/h2&gt;

&lt;p&gt;Define your environment variables in &lt;code&gt;deploy.yml&lt;/code&gt;:&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;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;HOSTNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;RAILS_SERVE_STATIC_FILES&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;RAILS_LOG_TO_STDOUT&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;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;KAMAL_REGISTRY_PASSWORD&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RAILS_MASTER_KEY&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Configure Accessories
&lt;/h2&gt;

&lt;p&gt;Set up your accessory services like PostgreSQL and Redis:&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;accessories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;myapp_production"&lt;/span&gt;
      &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
    &lt;span class="na"&gt;directories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;data:/var/lib/postgresql/data&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7.0&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;directories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;data:/data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rails Database Configuration
&lt;/h3&gt;

&lt;p&gt;Update your Rails database configuration in &lt;code&gt;config/database.yml&lt;/code&gt;:&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;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["POSTGRES_PASSWORD"] %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp_production&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV["DB_HOST"] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 8: Configure Traefik
&lt;/h2&gt;

&lt;p&gt;Traefik handles TLS termination, HTTPS redirect, and zero downtime deployments. Add the following configuration to &lt;code&gt;deploy.yml&lt;/code&gt;:&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;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;publish&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;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;volume&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;/letsencrypt/acme.json:/letsencrypt/acme.json"&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.web.address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:80"&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.websecure.address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:443"&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.web.http.redirections.entryPoint.to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;websecure&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.web.http.redirections.entryPoint.scheme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.web.http.redirections.entrypoint.permanent&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;certificatesResolvers.letsencrypt.acme.email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support@intellecta.app"&lt;/span&gt;
    &lt;span class="na"&gt;certificatesResolvers.letsencrypt.acme.storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/letsencrypt/acme.json"&lt;/span&gt;
    &lt;span class="na"&gt;certificatesResolvers.letsencrypt.acme.httpchallenge&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;certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 9: Deployment Commands
&lt;/h2&gt;

&lt;p&gt;Run the following commands to set up and deploy your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kamal setup
kamal &lt;span class="nb"&gt;env &lt;/span&gt;push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After 210 seconds, your app will be live. To deploy changes, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kamal deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 10: Troubleshooting Logs
&lt;/h2&gt;

&lt;p&gt;If there are issues, check the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kamal traefik logs
kamal app logs 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For live logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kamal app logs &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 11: Access Rails Console
&lt;/h2&gt;

&lt;p&gt;Access the Rails console using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kamal app &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"bin/rails c"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 12: Access Bash on Server
&lt;/h2&gt;

&lt;p&gt;Access bash on the server using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kamal server &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;--interactive&lt;/span&gt; &lt;span class="s2"&gt;"/bin/bash"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final &lt;code&gt;config/deploy.yml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Here's the overall final look of your &lt;code&gt;config/deploy.yml&lt;/code&gt;:&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="c1"&gt;# Name of your application. Used to uniquely configure containers.&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;myapp&lt;/span&gt;

&lt;span class="c1"&gt;# Name of the container image.&lt;/span&gt;
&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;username/myapp&lt;/span&gt;

&lt;span class="c1"&gt;# Deploy to these servers.&lt;/span&gt;
&lt;span class="na"&gt;servers&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;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;traefik.http.routers.messi-web.rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Host(`intellecta.app`)&lt;/span&gt;
      &lt;span class="na"&gt;traefik.http.routers.messi-web.tls&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;traefik.http.routers.messi-web.entrypoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;websecure&lt;/span&gt;
      &lt;span class="na"&gt;traefik.http.routers.messi-web.tls.certresolver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt&lt;/span&gt;

  &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;cmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bundle exec sidekiq -q high_priority -q default -q mailers&lt;/span&gt;

&lt;span class="c1"&gt;# Credentials for your image host.&lt;/span&gt;
&lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Specify the registry server, if you're not using Docker Hub&lt;/span&gt;
  &lt;span class="c1"&gt;# server: registry.digitalocean.com / ghcr.io / ...&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shahzaib&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;KAMAL_REGISTRY_PASSWORD&lt;/span&gt;

&lt;span class="c1"&gt;# Inject ENV variables into containers (secrets come from .env).&lt;/span&gt;
&lt;span class="c1"&gt;# Remember to run `kamal env push` after making changes!&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;HOSTNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;RAILS_SERVE_STATIC_FILES&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;RAILS_LOG_TO_STDOUT&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;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;KAMAL_REGISTRY_PASSWORD&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RAILS_MASTER_KEY&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL&lt;/span&gt;

&lt;span class="c1"&gt;# Use accessory services (secrets come from .env).&lt;/span&gt;
&lt;span class="na"&gt;accessories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;myapp_production"&lt;/span&gt;
      &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD&lt;/span&gt;
    &lt;span class="na"&gt;directories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;data:/var/lib/postgresql/data&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7.0&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.1&lt;/span&gt;
    &lt;span class="na"&gt;directories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;data:/data&lt;/span&gt;

&lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;publish&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;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;volume&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;/letsencrypt/acme.json:/letsencrypt/acme.json"&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.web.address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:80"&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.websecure.address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:443"&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.web.http.redirections.entryPoint.to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;websecure&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.web.http.redirections.entryPoint.scheme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https&lt;/span&gt;
    &lt;span class="na"&gt;entryPoints.web.http.redirections.entrypoint.permanent&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;certificatesResolvers.letsencrypt.acme.email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support@intellecta.app"&lt;/span&gt;
    &lt;span class="na"&gt;certificatesResolvers.letsencrypt.acme.storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/letsencrypt/acme.json"&lt;/span&gt;
    &lt;span class="na"&gt;certificatesResolvers.letsencrypt.acme.httpchallenge&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;certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By following these steps, you can easily deploy your Rails 7+ application using the&lt;/p&gt;

&lt;p&gt;Kamal gem on Digital Ocean. This guide should help you set up a robust, production-ready environment with minimal effort. Happy deploying!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>docker</category>
      <category>kamal</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Enhance Your Rails 7 App with Stimulus.js and JavaScript Integration</title>
      <dc:creator>Shah Zaib</dc:creator>
      <pubDate>Thu, 25 Jul 2024 00:05:41 +0000</pubDate>
      <link>https://dev.to/shahzaib/enhance-your-rails-7-app-with-stimulusjs-and-javascript-integration-5clf</link>
      <guid>https://dev.to/shahzaib/enhance-your-rails-7-app-with-stimulusjs-and-javascript-integration-5clf</guid>
      <description>&lt;h1&gt;
  
  
  Enhance Your Rails 7 App with Stimulus.js and JavaScript Integration
&lt;/h1&gt;

&lt;p&gt;Stimulus.js is a modest JavaScript framework that augments your HTML. It's the perfect companion for Rails' built-in functionality. In this post, we'll explore how to use Stimulus.js for JavaScript functionality, integrate it with other JavaScript libraries, and manage JavaScript dependencies effectively using Importmap.&lt;/p&gt;

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

&lt;p&gt;Before we begin, ensure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rails 7 application setup&lt;/li&gt;
&lt;li&gt;Basic knowledge of JavaScript and Rails&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up Stimulus.js in Rails 7
&lt;/h2&gt;

&lt;p&gt;Rails 7 comes with default support for Stimulus.js. To get started, ensure Stimulus is included in your application by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails new my_app
&lt;span class="nb"&gt;cd &lt;/span&gt;my_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find the Stimulus controllers in &lt;code&gt;app/javascript/controllers&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Stimulus Controller
&lt;/h2&gt;

&lt;p&gt;Let's create a Stimulus controller to handle a simple click event. 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 generate stimulus hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generate a new controller &lt;code&gt;hello_controller.js&lt;/code&gt; in &lt;code&gt;app/javascript/controllers&lt;/code&gt;. Open the file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/javascript/controllers/hello_controller.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@hotwired/stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, Stimulus!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your HTML, use the Stimulus controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;data-controller=&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;data-hello-target=&lt;/span&gt;&lt;span class="s"&gt;"output"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;data-action=&lt;/span&gt;&lt;span class="s"&gt;"click-&amp;gt;hello#greet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Greet&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the button is clicked, the text will change to "Hello, World!".&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating with Other JavaScript Libraries
&lt;/h2&gt;

&lt;p&gt;Stimulus.js can work seamlessly with other JavaScript libraries. For example, let's integrate jQuery with Stimulus.js.&lt;/p&gt;

&lt;p&gt;First, add jQuery using Importmap:&lt;/p&gt;

&lt;p&gt;Add jQuery to your &lt;code&gt;config/importmap.rb&lt;/code&gt;:&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;pin&lt;/span&gt; &lt;span class="s2"&gt;"jquery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, import jQuery in your Stimulus controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/javascript/controllers/hello_controller.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@hotwired/stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jquery&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, Stimulus!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputTarget&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fadeOut&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;fadeIn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, jQuery!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Managing JavaScript Dependencies
&lt;/h2&gt;

&lt;p&gt;Managing JavaScript dependencies in Rails 7 is straightforward with Importmap. Here are some tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Add a library:&lt;/strong&gt; Use &lt;code&gt;pin "library_name", to: "library_url"&lt;/code&gt; in your &lt;code&gt;config/importmap.rb&lt;/code&gt; to add a new library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remove a library:&lt;/strong&gt; Remove the corresponding line from &lt;code&gt;config/importmap.rb&lt;/code&gt; to remove an existing library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update libraries:&lt;/strong&gt; Update the URLs in &lt;code&gt;config/importmap.rb&lt;/code&gt; to the latest versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check outdated libraries:&lt;/strong&gt; Visit the URLs in &lt;code&gt;config/importmap.rb&lt;/code&gt; to see if newer versions are available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also add custom JavaScript files to your project. Place them in the &lt;code&gt;app/javascript&lt;/code&gt; folder and import them where needed.&lt;/p&gt;

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

&lt;p&gt;Stimulus.js provides a powerful yet simple way to add JavaScript functionality to your Rails application. By integrating it with other JavaScript libraries, you can create a rich and dynamic user experience. Properly managing your JavaScript dependencies ensures your application remains maintainable and up-to-date.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>javascript</category>
      <category>stimulus</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Solving Common Issues with Hotwire in Ruby on Rails: Tips and Tricks</title>
      <dc:creator>Shah Zaib</dc:creator>
      <pubDate>Sat, 20 Jul 2024 06:49:13 +0000</pubDate>
      <link>https://dev.to/shahzaib/solving-common-issues-with-hotwire-in-ruby-on-rails-tips-and-tricks-5ah5</link>
      <guid>https://dev.to/shahzaib/solving-common-issues-with-hotwire-in-ruby-on-rails-tips-and-tricks-5ah5</guid>
      <description>&lt;p&gt;&lt;strong&gt;Solving Common Issues with Hotwire in Ruby on Rails: Tips and Tricks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a Transformational Full-Stack Developer with expertise in Ruby on Rails and Hotwire, I’ve encountered and overcome various challenges when integrating Hotwire into Rails applications. In this post, I’ll share solutions to some common issues you might face, along with tips and tricks to enhance your development process.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handling Turbo Stream Errors&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One common issue developers face is dealing with Turbo Stream errors. Turbo Streams make it easy to update parts of your page, but sometimes things don’t go as planned. Here’s a quick tip to debug and fix these issues:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Check the Server Logs:&lt;/strong&gt; Ensure your Turbo Stream response is correctly formatted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate Turbo Frame IDs:&lt;/strong&gt; Make sure the IDs in your Turbo Frames and Streams match correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;debugger&lt;/code&gt; in JavaScript:&lt;/strong&gt; Place a &lt;code&gt;debugger&lt;/code&gt; statement in your Stimulus controller to pause execution and inspect the state.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;debugger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This will pause execution in the browser's dev tools&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Turbo Drive Navigation Issues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Another frequent problem is navigation issues with Turbo Drive, especially when dealing with forms and redirects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disable Turbo Drive for Specific Links or Forms:&lt;/strong&gt; Use &lt;code&gt;data-turbo="false"&lt;/code&gt; to opt-out of Turbo Drive for specific elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle Form Submissions Carefully:&lt;/strong&gt; Ensure your forms handle redirects properly by returning &lt;code&gt;turbo_stream&lt;/code&gt; responses.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form_with&lt;/span&gt; &lt;span class="ss"&gt;model: &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;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;turbo: &lt;/span&gt;&lt;span class="kp"&gt;false&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;form&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- form fields --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Stimulus Controller Initialization Problems&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stimulus controllers are fantastic for adding interactivity, but sometimes they don’t initialize as expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Check Your HTML:&lt;/strong&gt; Make sure your data-controller attribute matches your controller’s name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initialize Manually:&lt;/strong&gt; If necessary, you can initialize controllers manually in your JavaScript.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Application&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyController&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./my_controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyController&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Debugging Cable Ready and Stimulus Reflex&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When using Cable Ready and Stimulus Reflex, debugging can become tricky due to the real-time nature of these tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use the JavaScript Console:&lt;/strong&gt; Log useful information to the console to track what’s happening.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check Network Requests:&lt;/strong&gt; Inspect WebSocket frames in the network tab of your browser’s developer tools to ensure data is being transmitted correctly.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CableReady&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cable_ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;consumer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./consumer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MyChannel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;received&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cableReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;CableReady&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;By addressing these common issues and leveraging these tips and tricks, you can enhance your Hotwire and Rails development experience. Remember, the key to mastering these tools lies in persistent learning and practical application.&lt;/p&gt;

&lt;p&gt;If you have any questions or need further assistance, feel free to leave a comment below or reach out to me directly. Happy coding!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>hotwire</category>
      <category>webdev</category>
      <category>stimulus</category>
    </item>
  </channel>
</rss>
