<?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: Ackshaey Singh</title>
    <description>The latest articles on Forem by Ackshaey Singh (@ackshaey).</description>
    <link>https://forem.com/ackshaey</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%2F500276%2Ff411ff42-7a75-4f21-9255-c1ef125c62f2.jpg</url>
      <title>Forem: Ackshaey Singh</title>
      <link>https://forem.com/ackshaey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ackshaey"/>
    <language>en</language>
    <item>
      <title>The 30-Second Hack That Will Speed Up Your Coding More Than Any Framework</title>
      <dc:creator>Ackshaey Singh</dc:creator>
      <pubDate>Wed, 17 Dec 2025 20:43:09 +0000</pubDate>
      <link>https://forem.com/ackshaey/the-30-second-hack-that-will-speed-up-your-coding-more-than-any-framework-2men</link>
      <guid>https://forem.com/ackshaey/the-30-second-hack-that-will-speed-up-your-coding-more-than-any-framework-2men</guid>
      <description>&lt;p&gt;As software engineers we're always chasing the next productivity tool. A faster build system. A smarter IDE. A new framework that promises to 10x our output.&lt;/p&gt;

&lt;p&gt;More than anything else, this setting makes more of a tangible difference to my daily coding speed than any tool I've adopted over the past decade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sound familiar?
&lt;/h2&gt;

&lt;p&gt;Think about how much time you spend holding down keys:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scrolling through terminal output with arrow keys&lt;/li&gt;
&lt;li&gt;Deleting a line with backspace&lt;/li&gt;
&lt;li&gt;Moving through code with hjkl in vim&lt;/li&gt;
&lt;li&gt;Navigating long file paths in the shell&lt;/li&gt;
&lt;li&gt;Holding down arrow keys to select text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, MacOS has conservative key repeat settings - which makes sense because Apple doesn't tailor MacOS out of the box for keyboard first use. When you hold a key, there's a 225ms delay before it starts repeating, then it repeats every 30ms. That might not sound slow, but over thousands of operations per day, it adds up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I estimate this costs the average terminal-heavy developer 15-20 minutes per day.&lt;/strong&gt; That's scrolling lag. Waiting for the cursor to catch up. The micro-frustration of mashing delete harder because it feels too slow. Over a year? That's roughly &lt;strong&gt;80 hours of your life spent waiting for keys to repeat.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Do this
&lt;/h2&gt;

&lt;p&gt;MacOS allows you to set key repeat values below the System Preferences minimums via the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;defaults write &lt;span class="nt"&gt;-g&lt;/span&gt; InitialKeyRepeat &lt;span class="nt"&gt;-int&lt;/span&gt; 10  &lt;span class="c"&gt;# 150ms delay (default: 225ms)&lt;/span&gt;
defaults write &lt;span class="nt"&gt;-g&lt;/span&gt; KeyRepeat &lt;span class="nt"&gt;-int&lt;/span&gt; 2          &lt;span class="c"&gt;# 30ms repeat (already at GUI minimum)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you want ludicrous speed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;defaults write &lt;span class="nt"&gt;-g&lt;/span&gt; InitialKeyRepeat &lt;span class="nt"&gt;-int&lt;/span&gt; 10
defaults write &lt;span class="nt"&gt;-g&lt;/span&gt; KeyRepeat &lt;span class="nt"&gt;-int&lt;/span&gt; 1          &lt;span class="c"&gt;# 15ms repeat (2x faster than GUI minimum)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Log out and log back in&lt;/strong&gt; for changes to take effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Developers
&lt;/h2&gt;

&lt;p&gt;Terminal scrolling alone is transformative. When you run a test suite or check git logs, you're not just scrolling—you're &lt;strong&gt;scanning&lt;/strong&gt; for errors, searching for context, navigating to specific lines. With default settings, you're fighting the UI. With these settings, the terminal keeps pace with your eyes.&lt;/p&gt;

&lt;p&gt;The same applies to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code navigation&lt;/strong&gt;: Moving through files in vim/emacs at the speed of thought&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editing&lt;/strong&gt;: Deleting/rewriting code without the frustrating "hurry up" feeling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command line&lt;/strong&gt;: Fixing typos and navigating bash history instantly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Start Conservative
&lt;/h2&gt;

&lt;p&gt;I recommend starting with &lt;code&gt;KeyRepeat=2&lt;/code&gt; rather than 1. The difference between 30ms and 15ms is enormous—1 can feel almost too fast if you're not used to it. Give yourself a day to adjust.&lt;/p&gt;

&lt;p&gt;If you want to go back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;defaults delete &lt;span class="nt"&gt;-g&lt;/span&gt; InitialKeyRepeat
defaults delete &lt;span class="nt"&gt;-g&lt;/span&gt; KeyRepeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Decade Later, Still the Best Hack
&lt;/h2&gt;

&lt;p&gt;I've switched between dozens of editors, languages, and frameworks. I've adopted and abandoned countless productivity tools. But this setting? &lt;strong&gt;I notice within 5 seconds when it's missing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's why, after setting up my new MacBook and feeling that familiar sluggishness, I had to write this down.&lt;/p&gt;

&lt;p&gt;YMMV. But if you spend hours in the terminal every day, this is the fastest way to speed up your development workflow. Not a new language. Not a better framework. Just two commands and a logout.&lt;/p&gt;

&lt;p&gt;Try it for a day. I bet you'll never go back.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Harnessing Client-Side Caching in Rails: The Power of `expires_in`</title>
      <dc:creator>Ackshaey Singh</dc:creator>
      <pubDate>Thu, 05 Oct 2023 12:17:26 +0000</pubDate>
      <link>https://forem.com/ackshaey/harnessing-client-side-caching-in-rails-the-power-of-expiresin-1686</link>
      <guid>https://forem.com/ackshaey/harnessing-client-side-caching-in-rails-the-power-of-expiresin-1686</guid>
      <description>&lt;p&gt;In your journey as a software developer, you'll encounter myriad tools and techniques designed to optimize and streamline web applications. One such tool, often overlooked, is client-side caching. As backend and full-stack engineers, we spend hours crafting complex caching layers on the backend. However, we often overlook the most effective caching technique: having the request never reach the backend! Let's delve into how requests get cached on the client using the &lt;code&gt;Cache-Control&lt;/code&gt; header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Control Header
&lt;/h2&gt;

&lt;p&gt;At the core of client-side caching is the HTTP &lt;code&gt;Cache-Control&lt;/code&gt; header. This header offers directives to browsers (and other caching agents) about how they should cache the content and when to consider it stale.&lt;/p&gt;

&lt;p&gt;The most common directives include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;max-age&lt;/strong&gt;: Specifies the number of seconds the response remains fresh.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;no-cache&lt;/strong&gt;: Directs caching agents to revalidate with the server before using the cached version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;public/private&lt;/strong&gt;: &lt;code&gt;public&lt;/code&gt; means that any cache, including CDNs, can store the response. &lt;code&gt;private&lt;/code&gt; ensures the response is user-specific and only cached at the end-user level.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By setting the appropriate cache control headers, developers can steer the caching behavior of browsers and intermediaries, thereby optimizing both server load and user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rails &lt;code&gt;expires_in&lt;/code&gt; in Controller Actions
&lt;/h2&gt;

&lt;p&gt;In the Rails ecosystem, the &lt;code&gt;expires_in&lt;/code&gt; method is our key to effortlessly managing the cache control header. Within the context of Rails actions, using &lt;code&gt;expires_in&lt;/code&gt; sets the &lt;code&gt;Cache-Control&lt;/code&gt; header on the HTTP response.&lt;/p&gt;

&lt;p&gt;Take, for instance, an application like &lt;a href="https://designerdiscount.club" rel="noopener noreferrer"&gt;Designer Discount Club&lt;/a&gt; I'm currently building. The product data updates roughly once a day, and constructing the response requires complex queries and interactions with multiple services. Below, the &lt;code&gt;display_cards&lt;/code&gt; action powers an infinite scroll list on the client. By implementing &lt;code&gt;expires_in 1.hour, public: true&lt;/code&gt;, we essentially direct clients to retain and reuse their cached response for an hour. When users navigate back and forth, adding this cache control header reduces ~100ms round trip time from the client's perspective and diminishes request volume to our backend Redis cache by over 60%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqa9gpllohnuq2iqrll8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqa9gpllohnuq2iqrll8.png" alt="Designer Discount Club Page" width="800" height="631"&gt;&lt;/a&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="no"&gt;CLIENT_CACHE_EXPIRY_DURATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hour&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;display_cards&lt;/span&gt;
    &lt;span class="c1"&gt;# ... expensive queries and requests to backend caches to build `response`&lt;/span&gt;

    &lt;span class="n"&gt;expires_in&lt;/span&gt; &lt;span class="no"&gt;CLIENT_CACHE_EXPIRY_DURATION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;public: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Set the Cache-Control header&lt;/span&gt;

    &lt;span class="n"&gt;respond_to&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: :ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;mimetype: &lt;/span&gt;&lt;span class="no"&gt;Mime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:json&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;protobuf&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;plain: &lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_proto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: :ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;mimetype: &lt;/span&gt;&lt;span class="no"&gt;Mime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:protobuf&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fef6qlq10cie4vqa7gjet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fef6qlq10cie4vqa7gjet.png" alt="Developer tools screenshot" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Subtleties of &lt;code&gt;expires_in&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;When utilizing &lt;code&gt;expires_in&lt;/code&gt; in your controller actions, it's pivotal to understand its various options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time Duration&lt;/strong&gt;: This determines the freshness duration. Be it &lt;code&gt;30.minutes&lt;/code&gt; or &lt;code&gt;1.day&lt;/code&gt;, ensure it matches your application's data refresh cycle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Public/Private Directive&lt;/strong&gt;: &lt;code&gt;public: true&lt;/code&gt; indicates any cache, including CDNs, can store the response. In contrast, &lt;code&gt;private: true&lt;/code&gt; refers to user-specific data that should only be cached at the user level.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Other Directives&lt;/strong&gt;: Directives like &lt;code&gt;must_revalidate&lt;/code&gt; can be used for nuanced cache control. With &lt;code&gt;must_revalidate&lt;/code&gt;, once data becomes stale, it must be re-validated with the server before being reused.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there you have it! I've deliberately left out the many other splendid backend caching techniques integrated into Rails and those used by the &lt;code&gt;display_cards&lt;/code&gt; endpoint above; those will be the subject of another post. Before signing off, here are some plugs for my projects:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Preparing for a software engineering interview but loathe grinding LeetCode? I crafted &lt;a href="https://firecode.io" rel="noopener noreferrer"&gt;Firecode.io&lt;/a&gt; precisely for that reason. Give it a whirl!&lt;/p&gt;

&lt;p&gt;Fancy buying furniture at 20-30% designer and trade discounts without the need to hire an interior designer? Swing by &lt;a href="https://designerdiscount.club" rel="noopener noreferrer"&gt;Designer Discount Club&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>rails</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Feature flags in Rails: How to roll out and manage your features like a pro</title>
      <dc:creator>Ackshaey Singh</dc:creator>
      <pubDate>Thu, 06 Apr 2023 14:10:35 +0000</pubDate>
      <link>https://forem.com/ackshaey/feature-flags-in-rails-how-to-roll-out-and-manage-your-features-like-a-pro-1l7</link>
      <guid>https://forem.com/ackshaey/feature-flags-in-rails-how-to-roll-out-and-manage-your-features-like-a-pro-1l7</guid>
      <description>&lt;p&gt;Feature flagging is a widely adopted technique used in software development that enables developers to turn features or sections of their code on or off for different groups of users. It allows for the gradual release of new features to subsets of users, which makes it easier to test and monitor performance before enabling it for everyone. It provides developers with more flexibility and control over their releases, which can help avoid potential issues or rollbacks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F14800fo3i1gd78weksg1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F14800fo3i1gd78weksg1.png" alt="Features"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, imagine a team is working on a new feature that involves a significant change to the login process for a web app. Without feature flagging, the team would have to deploy the new code to everyone at once, potentially causing breaking the web app for all users. With feature flagging, the team can gradually enable the new login process for specific groups of users, testing and monitoring performance along the way. If any issues arise, the team can quickly turn off the feature flag to avoid widespread issues.&lt;/p&gt;

&lt;p&gt;Even if you’re working on your own solo developer low throughput Rails app, feature flagging can be useful in isolating and eliminating problematic releases. I recently had to implement a feature flag system for &lt;a href="https://firecode.io" rel="noopener noreferrer"&gt;Firecode.io&lt;/a&gt;, which is written primarily in Rails. In this blog post, we will look at how to use the &lt;a href="https://github.com/jnunemaker/flipper" rel="noopener noreferrer"&gt;Flipper&lt;/a&gt; gem to implement a basic feature flagging system in a Rails application. I have taken semi real examples and code from Firecode.io to illustrate the implementation with an example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Add the Flipper Gem to Your Gemfile
&lt;/h2&gt;

&lt;p&gt;To get started with Flipper, add the following lines to your Gemfile:&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;### Feature flagging with Flipper&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'flipper'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'flipper-active_record'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'flipper-ui'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These gems provide the core functionality for feature flagging with Flipper, as well as a user interface for managing your feature flags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Configure Flipper in Your Application
&lt;/h2&gt;

&lt;p&gt;Next, create a file &lt;code&gt;flipper.rb&lt;/code&gt; in your &lt;code&gt;config/initializers&lt;/code&gt; directory, and add code for configuring user groups. In this example we have created two user groups which can be accessed in the Flipper UI, and features can be enabled or disabled for these groups individually.  &lt;/p&gt;

&lt;p&gt;This code registers two feature blocks with Flipper: &lt;code&gt;:admin_user&lt;/code&gt; and &lt;code&gt;:patron&lt;/code&gt;. These blocks define the policy for enabling or disabling the features based on the properties of the current user. As an example, Firecode.io offers many perks that are reserved for Patrons, and the &lt;code&gt;:patron&lt;/code&gt; policy block we can apply features that are active only for Patrons.&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;# Initializer for the Flipper gem. Setups up the Flipper UI and registers&lt;/span&gt;
&lt;span class="c1"&gt;# feature groups.&lt;/span&gt;

&lt;span class="c1"&gt;# admin_user policy block&lt;/span&gt;
&lt;span class="no"&gt;Flipper&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="ss"&gt;:admin_user&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;actor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond_to?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:admin?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;admin?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# patron policy block&lt;/span&gt;
&lt;span class="no"&gt;Flipper&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="ss"&gt;:patron&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;actor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond_to?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:patron?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;patron?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Mount the Flipper UI in Your Application
&lt;/h2&gt;

&lt;p&gt;To make it easy to manage your feature flags, you can mount the Flipper UI in your application. To do this, add the following code to your &lt;code&gt;config/routes.rb&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# Flipper for feature flags&lt;/span&gt;
  &lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'/flipper'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;constraints: &lt;/span&gt;&lt;span class="no"&gt;RoleConstraint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:manage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code mounts the Flipper UI at the &lt;code&gt;/flipper&lt;/code&gt; endpoint in your application. The &lt;code&gt;RoleConstraint&lt;/code&gt; class is used to restrict access to the UI to users who have the &lt;code&gt;manage&lt;/code&gt; role. You can customize this constraint to suit your specific needs. In this case, we're using the &lt;a href="https://github.com/CanCanCommunity/cancancan" rel="noopener noreferrer"&gt;CanCanCan&lt;/a&gt; gem to gate specific routes to admin users. If you haven't worked with CanCanCan before, ignore the &lt;code&gt;RoleConstraint&lt;/code&gt; portion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: (Optional) Create a Features Repository and test it
&lt;/h2&gt;

&lt;p&gt;To make it easy to manage the feature symbols and check the state of your feature flags in your application code, you can create a &lt;code&gt;FeaturesRepo&lt;/code&gt; module that provides a simple API for checking the state of your feature flags. Create a file called &lt;code&gt;features_repo.rb&lt;/code&gt; in an &lt;code&gt;app/repositories&lt;/code&gt; directory, and add the following code:&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;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="c1"&gt;# Repository of feature flags. Uses the Flipper gem to manage feature flags.&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;FeaturesRepo&lt;/span&gt;
  &lt;span class="c1"&gt;# All feature flags should be defined here. Do not use strings.&lt;/span&gt;
  &lt;span class="no"&gt;FORWARD_INCOMING_WEBHOOKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:forward_incoming_webhooks&lt;/span&gt;

  &lt;span class="c1"&gt;# Returns the feature flag value for a given feature&lt;/span&gt;
  &lt;span class="c1"&gt;# @param feature [Symbol] the feature to check&lt;/span&gt;
  &lt;span class="c1"&gt;# @return [Boolean] the feature flag value&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Enables a feature flag&lt;/span&gt;
  &lt;span class="c1"&gt;# @param feature [Symbol] the feature to enable&lt;/span&gt;
  &lt;span class="c1"&gt;# @return [Boolean] the feature flag value&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Disables a feature flag&lt;/span&gt;
  &lt;span class="c1"&gt;# @param feature [Symbol] the feature to disable&lt;/span&gt;
  &lt;span class="c1"&gt;# @return [Boolean] the feature flag value&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code defines a module called &lt;code&gt;FeaturesRepo&lt;/code&gt; that provides methods for checking the state of your feature flags. The &lt;code&gt;FORWARD_INCOMING_WEBHOOKS&lt;/code&gt; constant is defined as an example of a feature flag that can be used in your application code - we’ll take a look at how it is used below.  &lt;/p&gt;

&lt;p&gt;You should also create a test for this repo, just in case the Flipper API changes in the future or if our AI overlords generate garbage code and break our app. Create a file &lt;code&gt;test/repositories/features_repo_test.rb&lt;/code&gt; with the following tests:&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;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'test_helper'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'minitest/autorun'&lt;/span&gt;

&lt;span class="c1"&gt;# Tests for the FeaturesRepo module&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FeaturesRepoTest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestCase&lt;/span&gt;
  &lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;print_test_case_running&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;teardown&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;print_test_case_pass&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s1"&gt;'enabled? should return false if a feature is disabled'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt; &lt;span class="ss"&gt;:test_feature&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:test_feature&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s1"&gt;'enabled? should return true if a feature is enabled'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt; &lt;span class="ss"&gt;:test_feature&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:test_feature&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s1"&gt;'enable should enable a feature'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt; &lt;span class="ss"&gt;:test_feature&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:test_feature&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt; &lt;span class="ss"&gt;:test_feature&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:test_feature&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s1"&gt;'disable should disable a feature'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt; &lt;span class="ss"&gt;:test_feature&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:test_feature&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt; &lt;span class="ss"&gt;:test_feature&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:test_feature&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Use Feature Flags in Your Application Code
&lt;/h2&gt;

&lt;p&gt;Now that you have set up Flipper and created a repository for your feature flags, you can start using feature flags in your application code. For example, here is some semi real code from Firecode.io for a &lt;code&gt;WebhooksController&lt;/code&gt; that checks the state of a feature flag before forwarding incoming webhooks to Slack - it has been (over) simplified for conciseness, always remember to sanitize any external data before forwarding it to other destinations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebhooksController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="c1"&gt;# Bypass authenticity token check since we are receiving webhooks from external services&lt;/span&gt;
  &lt;span class="n"&gt;skip_before_action&lt;/span&gt; &lt;span class="ss"&gt;:verify_authenticity_token&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enabled?&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FORWARD_INCOMING_WEBHOOKS&lt;/span&gt;
      &lt;span class="no"&gt;ForwardService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="n"&gt;build_forward_request_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="no"&gt;ApiConstants&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EMPTY_JSON_RECEIVED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: :ok&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;This code checks the state of the &lt;code&gt;FORWARD_INCOMING_WEBHOOKS&lt;/code&gt; feature flag before forwarding incoming webhooks. If the feature flag is disabled, the message is not forwarded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Test Your Feature Flags
&lt;/h2&gt;

&lt;p&gt;To ensure that your feature flags are working as expected, it is important to write tests that cover all of the possible scenarios. Here is an example test for the hypothetical &lt;code&gt;WebhooksController&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="c1"&gt;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'test_helper'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'sidekiq/testing'&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Api&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;V1&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebhooksControllerTest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;IntegrationTest&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;IntegrationHelpers&lt;/span&gt;
&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
      &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s1"&gt;'send should not use ForwardService to enqueue a SlackWorker job if the feature flag is disabled'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FORWARD_INCOMING_WEBHOOKS&lt;/span&gt;
        &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="vi"&gt;@send_path&lt;/span&gt;
        &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s1"&gt;'send should use ForwardService to enqueue a SlackWorker job if the feature flag is enabled'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="no"&gt;Flipper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt; &lt;span class="no"&gt;FeaturesRepo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FORWARD_INCOMING_WEBHOOKS&lt;/span&gt;
        &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="vi"&gt;@send_path&lt;/span&gt;
        &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SlackWorker'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'class'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you deploy this code to production or test it locally, you'll have to first create a feature flag called &lt;code&gt;forward_incoming_webhooks&lt;/code&gt; in the Flipper UI (mounted at /flipper and accessible to admin users) and enable it. Fortunately, the Flipper UI is awesome and makes managing features really easy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fl8ml1bitvqcbjn8v1dzx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fl8ml1bitvqcbjn8v1dzx.png" alt="Feature Disabled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fimrslh60fch9d0hh825a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fimrslh60fch9d0hh825a.png" alt="Feature Enabled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it! You now have a fully configured feature flagging system in your Rails app. Notice we didn’t cover some more advanced features that Flipper offers, including enabling features for a user group or individual users. For that, check out &lt;a href="https://github.com/jnunemaker/flipper" rel="noopener noreferrer"&gt;Flipper&lt;/a&gt; on Github. We also didn’t cover feature flagging frontend features in this post - if that becomes a requirement we could easily create an endpoint that uses the &lt;code&gt;FeaturesRepo&lt;/code&gt;  and sends enabled features to the frontend to toggle. If you learned something new consider following me here - I’ll be putting out more content on Ruby on Rails and software development as I work on Firecode.io. Preparing for a coding interview? Check out &lt;a href="https://firecode.io" rel="noopener noreferrer"&gt;Firecode.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Switching it up: how Tailwind CSS helped me create a dark mode logo in Rails</title>
      <dc:creator>Ackshaey Singh</dc:creator>
      <pubDate>Wed, 22 Mar 2023 12:12:25 +0000</pubDate>
      <link>https://forem.com/ackshaey/switching-it-up-how-tailwind-css-helped-me-create-a-dark-mode-logo-in-rails-5fjd</link>
      <guid>https://forem.com/ackshaey/switching-it-up-how-tailwind-css-helped-me-create-a-dark-mode-logo-in-rails-5fjd</guid>
      <description>&lt;p&gt;As someone that still swears by Bootstrap, I recently had the opportunity to try &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt;. I'm currently working on a new Rails 7 app for my wife, and I wanted to design a new logo for it. I used Illustrator to create the logo, and exported it as a PNG with a transparent background and white foreground. But I wanted to take it to the next level by adding a toggle between light and dark mode depending on the user's preference or the system settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F7sfo2dgc1qbkh1m7ppxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7sfo2dgc1qbkh1m7ppxb.png" alt="Adobe Illustrator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wasn't sure how to achieve this effect without writing custom CSS or exporting another version of the logo for light mode screens, but I knew that there had to be a better way to achieve the effect I wanted. Sure, I could write a custom style class in CSS for this, but then how do I check if dark mode is enabled as a system wide setting? Tailwind CSS to the rescue. After setting up Tailwind for my rails app, it was as simple as adding two utility classes to the logo in my &lt;code&gt;header.erb&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;&amp;lt;%= image_tag 'brand/1x/logo.lightmode.png', class: "h-full dark:filter dark:invert" %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These classes apply the &lt;code&gt;invert(1)&lt;/code&gt; function to the CSS property &lt;code&gt;filter&lt;/code&gt; , but only when system wide dark mode is enabled. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Furl17r555bokpcj45yej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Furl17r555bokpcj45yej.png" alt="Light mode demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F3jpds2yh2gl7abh69c3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F3jpds2yh2gl7abh69c3m.png" alt="Dark mode demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was such a timesaver and cut down quite a few hoops in getting the logo right. I’m still discovering other utility classes in Tailwind CSS, one thing I know for sure is I might finally ditch Bootstrap for Tailwind for new Rails apps.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Are you preparing for a coding interview? Check out &lt;a href="https://firecode.io" rel="noopener noreferrer"&gt;Firecode.io&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>rails</category>
      <category>tailwindcss</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>How to Setup Devise for User Authentication on Rails 7</title>
      <dc:creator>Ackshaey Singh</dc:creator>
      <pubDate>Mon, 20 Mar 2023 22:36:08 +0000</pubDate>
      <link>https://forem.com/ackshaey/how-to-setup-devise-for-user-authentication-on-rails-7-ojg</link>
      <guid>https://forem.com/ackshaey/how-to-setup-devise-for-user-authentication-on-rails-7-ojg</guid>
      <description>&lt;p&gt;If you are a frequent user of Ruby on Rails, you know that building authentication and user management systems can be a time-consuming and complex process. That’s where Devise comes in — a powerful authentication solution that simplifies the process of implementing user management systems in your Rails applications. As a Rails developer who churns out apps regularly, I’ve found myself reaching for Devise every single time. However, with the release of Rails 7, I’ve had to adjust my workflow and make sure that Devise works seamlessly with the new version. In this blog post, I’ll share my workflow for setting up Devise on Rails 7 and walk you through the steps to get started with this essential tool. So, whether you’re a seasoned Rails developer or just getting started, read on for a comprehensive guide to setting up Devise on Rails 7.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hang on, why should I use Devise?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fdrb9llzq6ka4hb4ekmn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fdrb9llzq6ka4hb4ekmn7.png" alt="Devise logo" width="300" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authenticating users in a web application is a critical task that requires careful consideration of security best&lt;br&gt;
practices. Building authentication functionality from scratch can be a daunting and time-consuming process, particularly&lt;br&gt;
for developers who are not well-versed in security principles. This is where Devise comes in handy. Devise provides a comprehensive and customizable solution that handles common authentication tasks such as user registration, login, and password resets, while also supporting various authentication mechanisms and providing robust security features. By using Devise, developers can save valuable time and ensure their application's authentication system is strong and reliable, allowing them to focus on building other aspects of their application. Let's see it in action on Rails 7.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before proceeding with the guide, ensure that you have a new or barebones Rails app created using &lt;code&gt;rails new&lt;/code&gt;.&lt;br&gt;
Additionally, you should not have a &lt;code&gt;User&lt;/code&gt; model set up yet.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step-by-Step Guide
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Add Devise, Letter Opener, and Omniauth (optional) to your Gemfile:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"devise"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"heartcombo/devise"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"f8d1ea90bc3"&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"omniauth"&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&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;gem&lt;/span&gt; &lt;span class="s2"&gt;"letter_opener"&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Note: cloning Devise from GitHub is necessary because it contains fixes for some Rails 7 incompatibilities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Install the gems:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the Devise install generator:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails g devise:install
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This generates the &lt;code&gt;devise.rb&lt;/code&gt; initializer and adds the &lt;code&gt;en&lt;/code&gt; locale at &lt;code&gt;config/locales/devise.en.yml&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Add the following Devise-specific configurations to &lt;code&gt;config/development.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# For Devise&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_url_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;host: &lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;port: &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;# For Letter Opener&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;action_mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delivery_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:letter_opener&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;action_mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform_deliveries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&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;action_mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_delivery_errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate the &lt;code&gt;User&lt;/code&gt; model with Devise:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails g devise user
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates the user model files as well as a preliminary migration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Edit the migration to add the fields you need:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;## Identifying fields&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:first_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:last_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default: &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, uncomment the &lt;code&gt;trackable&lt;/code&gt;, &lt;code&gt;confirmable&lt;/code&gt;, and &lt;code&gt;lockable&lt;/code&gt; fields (and accompanying indexes).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit &lt;code&gt;user.rb&lt;/code&gt; and add &lt;code&gt;confirmable&lt;/code&gt;, &lt;code&gt;trackable&lt;/code&gt;, &lt;code&gt;lockable&lt;/code&gt;, and &lt;code&gt;omniauthable&lt;/code&gt; to Devise.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tweak options in &lt;code&gt;config/devise.rb&lt;/code&gt; to suit your needs. For example, you may want to increase the &lt;code&gt;remember_for&lt;/code&gt;&lt;br&gt;
option to a couple of months:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remember_for&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;months&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the same file, change the default email to one from your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```ruby
config.mailer_sender = 'no-reply@designerdiscount.club'
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Generate the Devise views so you can modify them later:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails g devise:views
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Migrate the database:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   rake db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add the following code to &lt;code&gt;application.html.erb&lt;/code&gt; right above the &lt;code&gt;yield&lt;/code&gt; block:
&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;notice&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert alert-success"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;notice&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&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;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"alert alert-danger"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&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;ul&gt;
&lt;li&gt;&lt;p&gt;Try it out! Start your rails server and head to &lt;a href="http://localhost:3000/users/sign_up" rel="noopener noreferrer"&gt;http://localhost:3000/users/sign_up&lt;/a&gt; and create a new user. You should receive an email which opens in the browser (via letter_opener). Great, it’s working!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deny logged-out access to a controller action and test it out. Create a &lt;code&gt;home&lt;/code&gt; action in an existing controller,&lt;br&gt;
which is &lt;code&gt;PagesController&lt;/code&gt; in this example:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;
   &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PagesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
     &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;landing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

     &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s redirect the user to the landing page if they try to access &lt;code&gt;home&lt;/code&gt; but are logged out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;landing&lt;/span&gt;
     &lt;span class="n"&gt;redirect_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;action: :home&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="ss"&gt;params: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query_parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_signed_in?&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;home&lt;/span&gt;
     &lt;span class="n"&gt;redirect_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;action: :landing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="ss"&gt;params: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query_parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;user_signed_in?&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Edit the global header to hide the sign-in link if the user is signed in:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_signed_in?&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;'Logout'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destroy_user_session_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="ss"&gt;method: :delete&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_method: :delete&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s2"&gt;"Sign up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_user_registration_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;rel: &lt;/span&gt;&lt;span class="s1"&gt;'noopener noreferrer'&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s2"&gt;"Login"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_user_session_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;rel: &lt;/span&gt;&lt;span class="s1"&gt;'noopener noreferrer'&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/li&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;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it! You now have a basic setup for user authentication using Devise on Rails 7. You can customize the generated Devise views with Tailwind or Bootstrap to match your app’s design. Want to learn more? Check out the &lt;a href="https://github.com/heartcombo/devise#the-devise-wiki" rel="noopener noreferrer"&gt;Devise wiki&lt;/a&gt;. Preparing for a coding interview? Check out &lt;a href="https://firecode.io" rel="noopener noreferrer"&gt;Firecode.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ruby</category>
      <category>rails</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>So what exactly are those pesky versions in your package.json and Gemfiles anyway? An introduction to Semantic Versioning</title>
      <dc:creator>Ackshaey Singh</dc:creator>
      <pubDate>Tue, 14 Mar 2023 21:36:32 +0000</pubDate>
      <link>https://forem.com/ackshaey/so-what-exactly-are-those-pesky-versions-in-your-packagejson-and-gemfiles-anyway-an-introduction-to-semantic-versioning-2ccg</link>
      <guid>https://forem.com/ackshaey/so-what-exactly-are-those-pesky-versions-in-your-packagejson-and-gemfiles-anyway-an-introduction-to-semantic-versioning-2ccg</guid>
      <description>&lt;p&gt;You may not give it a second thought, but as a software engineer, you come across Semantic Versioning every day. Simply put, it's a way of standardizing how version numbers are assigned and interpreted. It follows a three-part numbering system: &lt;strong&gt;&lt;em&gt;Major.Minor.Patch&lt;/em&gt;&lt;/strong&gt;. And trust me, understanding what each number means can save you a lot of time and headaches down the line.&lt;/p&gt;

&lt;p&gt;Let's start with the &lt;strong&gt;PATCH&lt;/strong&gt; version. This level is for implementation level detail changes, like small bug fixes. It's denoted by a number in the form of 0.0.&lt;strong&gt;x&lt;/strong&gt;. So, if you see a new version of software that has changed the &lt;strong&gt;PATCH&lt;/strong&gt; number, you can safely update your code without worrying about backwards compatibility issues.&lt;/p&gt;

&lt;p&gt;Moving on to the &lt;strong&gt;MINOR&lt;/strong&gt; version, which is denoted by a number in the form of 0.&lt;strong&gt;x&lt;/strong&gt;.0. This level is for any backwards compatible API changes, like new functionality/features. So, if you see that a new &lt;strong&gt;MINOR&lt;/strong&gt; version has been released, you can safely update your code and expect it to work as expected.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;strong&gt;MAJOR&lt;/strong&gt; version, which is denoted by a number in the form of &lt;strong&gt;x&lt;/strong&gt;.0.0. This level is for backwards incompatible API changes, such as changes that will break existing users' code if they update. So, if you see that a new MAJOR version has been released, proceed with caution and make sure you thoroughly test your code before updating.&lt;/p&gt;

&lt;p&gt;Let's take an example. Suppose you want to build a toy 'magic-8-ball' application that can predict the future. Using semantic versioning, you might keep track of changes in your CHANGELOG like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;v0.1.0: Initial release, with the core 'magic-8-ball' prediction functionality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v0.2.0: Added color to the 8-ball because black and white is so last century.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v0.3.0: Added a 'shake' method that shakes the ball so you don't have to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v1.0.0: Added a 'reveal' method to see the prediction without shaking the ball. Breaking change: prediction string now includes question asked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v1.1.0: Added a 'history' method to view previous predictions. Backwards-compatible: still returns only the latest prediction by default.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v1.1.1: Fixed a bug in the 'history' method that prevented it from returning more than one prediction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v1.1.2: Fixed a bug in the 'reveal' method that was caused by the previous bug fix.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Semantic Versioning is a simple and powerful tool that can save you time and prevent headaches. Understanding what each number means can help you stay ahead of the game and make informed decisions when updating your code. So, next time you come across a new version of software, take a moment to check the version number and make sure you understand what each number means before updating!&lt;/p&gt;

&lt;p&gt;Want to learn more? Check out &lt;a href="https://semver.org"&gt;SemVer&lt;/a&gt;. Preparing for a software engineering interview? Checkout &lt;a href="https://firecode.io"&gt;Firecode.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>rails</category>
      <category>github</category>
    </item>
    <item>
      <title>Level up your JavaScript browser logs with these console.log() tips</title>
      <dc:creator>Ackshaey Singh</dc:creator>
      <pubDate>Mon, 02 Nov 2020 18:49:04 +0000</pubDate>
      <link>https://forem.com/ackshaey/level-up-your-javascript-browser-logs-with-these-console-log-tips-55o2</link>
      <guid>https://forem.com/ackshaey/level-up-your-javascript-browser-logs-with-these-console-log-tips-55o2</guid>
      <description>&lt;p&gt;I consider myself a backend software engineer - and as any backend engineer would attest, a large part of our life is spent monitoring, troubleshooting, and debugging our applications. The fundamental rule of software development is that software will fail - what separates new developers from experienced ones is how they plan for those failures. Robust and effective logging is an important part of planning for failure, and eventual mitigation. As it is for backend development, logging can be useful for frontend software development, but it goes much further than just troubleshooting and debugging. Effective frontend logging can also make the development experience productive, fast, and fun. &lt;/p&gt;

&lt;p&gt;While I’m a big proponent and diligent practitioner of Test-driven development, I love the flexibility, the richness of information, and code confidence browsers provide to frontend developers who make effective use of &lt;code&gt;console.log()&lt;/code&gt;. I thought I’d share some frontend logging tips and tricks I’ve learned and incorporated in my workflow over time while building &lt;a href="https://firecode.io" rel="noopener noreferrer"&gt;Firecode.io&lt;/a&gt; - in the hope that some of these will help you make your development workflow a bit more productive and fun!&lt;/p&gt;

&lt;p&gt;I like to divide these tips into two broad categories - quick n’ dirty logging for when you’re actively building and debugging your application, and  durable production logging - to know when your app’s working as expected and when it’s not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips for quick n’ dirty development logging with &lt;code&gt;console.log()&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Don’t use console.log().
&lt;/h3&gt;

&lt;p&gt;Yes, that’s right. I don’t use &lt;code&gt;console.log()&lt;/code&gt;. Well, ok I write wrappers that use &lt;code&gt;console.log()&lt;/code&gt; (more on that in the production logging section), but if you want to log something in your app to see what’s going on, use &lt;code&gt;console.trace()&lt;/code&gt; instead. In addition to giving you everything &lt;code&gt;console.log()&lt;/code&gt; does, it also outputs the entire stack trace so you know where exactly the message is emitted from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg87cv03r0q8qjt6405xq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg87cv03r0q8qjt6405xq.png" alt="02"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Use ES6’s computed property names to identify your objects and avoid variable name confusion
&lt;/h3&gt;

&lt;p&gt;This one is straightforward - use ES6’s computed property syntax and wrap the objects you wish to log in curly braces inside &lt;code&gt;console.log()&lt;/code&gt; - i.e. use &lt;code&gt;console.log({user})&lt;/code&gt; vs &lt;code&gt;console.log(user)&lt;/code&gt;. You’ll find them neatly logged with the variable name set as the key, and the value as the object itself. This is especially useful when you’re in a hurry and want to log multiple objects in the same &lt;code&gt;console.log()&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvxvffyxht8768nf5zxns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvxvffyxht8768nf5zxns.png" alt="03"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Embrace tiered log levels - error, warn, info
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;console.log(param)&lt;/code&gt; by default logs at the &lt;code&gt;INFO&lt;/code&gt; level - however, you also have 3 other logging levels at your disposal which you should make use of - &lt;code&gt;console.debug()&lt;/code&gt;, &lt;code&gt;console.warn()&lt;/code&gt; and &lt;code&gt;console.error()&lt;/code&gt;. Besides formatting differences (notice the different colors?), the browser’s developer console also lets you easily filter out logs at different levels with a convenient dropdown to declutter your logs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fue6ofcm2xsagy1moazhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fue6ofcm2xsagy1moazhm.png" alt="04"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp1exgw4wpithm5roqz3k.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp1exgw4wpithm5roqz3k.gif" alt="04"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  When logging lists of items, use console.table()
&lt;/h3&gt;

&lt;p&gt;This one is self-explanatory and one of my favorite console functions - if you ever need to log a list of objects, give &lt;code&gt;console.table()&lt;/code&gt; a try.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw4pojt1jpusdmxzh197s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw4pojt1jpusdmxzh197s.png" alt="05"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Quickly debug with &lt;code&gt;debugger&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Want to save a precious few seconds? Instead of finding your file in the developer console to add a breakpoint, drop a &lt;code&gt;debugger&lt;/code&gt; in your code to halt execution when the line is executed.  From this point on, you can debug and step over / into functions as you normally would.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff2a5wu93urj3vseiu9km.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff2a5wu93urj3vseiu9km.png" alt="06"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff8g64nypjsa184izvk4h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff8g64nypjsa184izvk4h.png" alt="08"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Granular performance profiling with &lt;code&gt;console.profile()&lt;/code&gt; and &lt;code&gt;console.time()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Want to profile an exact user flow in your application to find hot spots? Trigger &lt;code&gt;console.profile(profileName)&lt;/code&gt; at the start of the action, and &lt;code&gt;console.profileEnd(profileName)&lt;/code&gt; at the end to inspect the CPU profile for the flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmmwhq6y9v6g9h4cyfozu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmmwhq6y9v6g9h4cyfozu.png" alt="09"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnf9l86rj4xy1opslbeyc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnf9l86rj4xy1opslbeyc.gif" alt="10"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Related, you can measure exactly how long a flow takes with triggering &lt;code&gt;console.time(id)&lt;/code&gt; at the start of the flow, and &lt;code&gt;console.timeEnd(id)&lt;/code&gt; at the end. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftyy3zc7hisr4yofyvvap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftyy3zc7hisr4yofyvvap.png" alt="11"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Count labelled executions with &lt;code&gt;console.count()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This one’s one of those console functions I haven’t found much use for personally, but it’s there if you need it. &lt;code&gt;console.count(label)&lt;/code&gt; can help you know exactly how many times a piece of code gets executed - which could be useful for finding and eliminating race conditions and other scenarios.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F573ovm53jehapshlqb36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F573ovm53jehapshlqb36.png" alt="12"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Prettify your logging with CSS
&lt;/h3&gt;

&lt;p&gt;This is by far my favorite console feature and one I make extensive use of in production logging (more on this in the production logging section). You can make use of  format strings to format your log messages. The &lt;code&gt;%c&lt;/code&gt; is the placeholder for CSS styles, and anything after is your message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzbmsic8qu3e5pqe3c9am.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzbmsic8qu3e5pqe3c9am.png" alt="13"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You can also style multiple elements by extending your format string to include &lt;code&gt;%s&lt;/code&gt; for string parameters. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffbtlflkigkemdqd7vsae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffbtlflkigkemdqd7vsae.png" alt="14"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since I’m a highly visual person, I like to spend some time making my info and debug logs look pretty and be useful at the same time. I make extensive use of this feature for production logging in Firecode.io - which is an excellent segue for the next section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fln4g1ivwiqgc86egr26v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fln4g1ivwiqgc86egr26v.png" alt="15"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Production logging with &lt;code&gt;console.log()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Getting frontend code production ready involves a number of steps - some being uglifying and compressing your code, generating cacheable asset digests, and removing  &lt;code&gt;console.log()&lt;/code&gt; s from your app. Why? Because you don’t want your users to have to open the developer console to interact with your app, which nullifies the usefulness of your logs and leaves them as pure security holes for the more inquisitive to take advantage of. At the same time, when &lt;em&gt;you&lt;/em&gt; use your own app, you most likely want the most granular level of logging to understand how your app is functioning and find and squash bugs. If your app is being used by others, you’d also want to be notified when your application’s users encounter errors so you can track down and fix your code. Here’s a couple of things I do to satisfy these requirements as best one could on the frontend:&lt;/p&gt;

&lt;h3&gt;
  
  
  Don’t use console.log()
&lt;/h3&gt;

&lt;p&gt;Instead, write a wrapper class that includes logic for conditionally logging based on the log level based set on a global variable by the backend. Warning - you’ll see TypeScript code snippets ahead - if you’re not familiar with TypeScript, think of it as a superset of JavaScript with types tacked on (gross over-simplification) - i.e. &lt;code&gt;const str = “some string”;&lt;/code&gt; becomes &lt;code&gt;const str: string = “some string”&lt;/code&gt; - types are added after a variable followed by a semicolon.&lt;/p&gt;

&lt;p&gt;In the case of Firecode.io, I wrote my own frontend framework that utilizes RxJS, but includes familiar concepts such as components from other popular frameworks such as React and Vue - while adding additional concepts such as engines for processor-heavy code blocks, channels for WebSocket messages, and clients for HTTP requests. Visualizing all these pieces working together was critical, so I implemented custom formatting in a &lt;code&gt;Logger&lt;/code&gt; wrapper class that formats and visually differentiates logs from each part of the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fze7utc9dr1qx7sfkqwsq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fze7utc9dr1qx7sfkqwsq.png" alt="17"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of calling &lt;code&gt;console.log("Cache SET to", {value})&lt;/code&gt;, I call &lt;code&gt;Logger.debug(“Cache set to”, {value}, Framework.Cache)&lt;/code&gt; . The &lt;code&gt;Logger&lt;/code&gt; class has a TypeScript enum that maps each framework component to the color to be used:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9l9aoiuctz9rprzfky2u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9l9aoiuctz9rprzfky2u.png" alt="18"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows me to visually focus on components of the app during development - for example, if I want to see what the &lt;code&gt;WsRequestCache&lt;/code&gt; is doing I can tune out everything else besides the turquoise badged logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protect your logs by having the backend set your log level
&lt;/h3&gt;

&lt;p&gt;I have Firecode.io configured to turn on debug level logging by default for admin users with a JavaScript variable that is set by the backend. While adventurous users can still find and set these flags in the developer console to turn on granular logging, it is better than having all logs exposed to every user of your application by default, or having a post-processor remove all logging completely from your application in production.&lt;/p&gt;

&lt;p&gt;Set in a Ruby on Rails view: &lt;br&gt;
&lt;code&gt;const logLevel: number = &amp;lt;%= @app.get_log_level_for_user %&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And in the Logger class:&lt;/p&gt;

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

class Logger {
   ...
   ...
   static info(...) {
     shouldLog(Level.INFO) &amp;amp;&amp;amp; console.log(...);
        ...
   }
}


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Log and notify on actionable errors
&lt;/h3&gt;

&lt;p&gt;Last but not least, you want to be notified when exceptional conditions are encountered by users without necessarily outputting logs to the developer console. You can do this by including a call to pipe your errors to a third party APM service such as &lt;a href="https://appsignal.com/r/3a311c33b0" rel="noopener noreferrer"&gt;AppSignal&lt;/a&gt; in your Logger‘s error function like so:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

class Logger {
   ...
   ...
   static error(e) {
     if (shouldLog(Level.ERROR)) {
       console.error(e);
     }
     appsignal.sendError(e);
   }
}


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://appsignal.com/r/3a311c33b0" rel="noopener noreferrer"&gt;AppSignal&lt;/a&gt; includes integrations to pipe your errors to outbound notifications services such as Slack, PagerDuty, and OpsGenie - you can even hook up a project management tool such as JIRA or Trello to automatically create issues and bugs for your team. &lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;I really hope these tips and anecdotes make your frontend development experience a little more productive and fun! I’ve obviously only touched the surface of logging ninjitsu in this post, so if you have any more tips to share I’d love to read them over on my &lt;a href="https://twitter.com/ackshaey" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fagzozoxegvkrz9pah69b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fagzozoxegvkrz9pah69b.png" alt="plug"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Two parting plugs - I’m rebuilding Firecode.io from the ground up with a brand new set of coding interview questions for JavaScript, Java, Python, and Scala. If you’re interested in coding interview prep that adapts to your learning style and is fun - sign up with your email &lt;a href="https://firecode.io" rel="noopener noreferrer"&gt;here&lt;/a&gt; I’ll also be putting out more content about building a production scale web app like Firecode.io from scratch as a side project - follow me at &lt;a href="https://twitter.com/ackshaey" rel="noopener noreferrer"&gt;@ackshaey&lt;/a&gt; or &lt;a href="https://twitter.com/firecodeio" rel="noopener noreferrer"&gt;@firecodeio&lt;/a&gt; to learn more. Lastly, if you’re new to JavaScript and want to understand how object-oriented JavaScript and prototypal inheritance work under the hood, check out my favorite book on the subject -  &lt;a href="https://amzn.to/2JhHB1V*" rel="noopener noreferrer"&gt;The Principles of Object-Oriented JavaScript&lt;/a&gt;, and if you’re interested in learning more about why you should use TypeScript instead, check out &lt;a href="https://amzn.to/3jQ5ZnQ" rel="noopener noreferrer"&gt;Effective TypeScript&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>productivity</category>
    </item>
    <item>
      <title>MacOS vs Linux — the cp command will trip you up!</title>
      <dc:creator>Ackshaey Singh</dc:creator>
      <pubDate>Tue, 27 Oct 2020 17:56:08 +0000</pubDate>
      <link>https://forem.com/ackshaey/macos-vs-linux-the-cp-command-will-trip-you-up-2p00</link>
      <guid>https://forem.com/ackshaey/macos-vs-linux-the-cp-command-will-trip-you-up-2p00</guid>
      <description>&lt;p&gt;While building &lt;a href="http://www.firecode.io" rel="noopener noreferrer"&gt;www.firecode.io&lt;/a&gt;, I was recently confronted with more than a hundred failing unit tests when running the test suite locally on my MacOS machine, rather than in a Linux Docker container the platform is configured to run tests in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fow4bvfthwbep03y3i8ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fow4bvfthwbep03y3i8ra.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use a MacBook Pro for software development, primarily because the BSD based MacOS provides a development experience that’s very similar to other Linux distros. All of my most frequently used navigation commands — &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, &lt;code&gt;mkdir&lt;/code&gt;, &lt;code&gt;touch&lt;/code&gt;, etc...work with 1:1 parity across both flavors of operating systems, or at least that’s what I thought. As I discovered after spending a good hour debugging these failures, there’s a subtle difference between the BSD and GNU implementations of the &lt;code&gt;cp -R&lt;/code&gt; command, which I got hit with when running my tests on different environments.&lt;/p&gt;

&lt;p&gt;Here’s the difference, illustrated with an example run in both MacOS and Linux:&lt;/p&gt;

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

# Creates "source_directory" in the current working directory
$ mkdir source_directory

# Creates 2 new empty files within "source_directory"
$ touch source_directory/{file1,file2}

# Creates "destination_directory" in the current working directory
$ mkdir destination_directory

# Intended to copy the contents of "source_directory" to "destination_directory", hence the trailing slashes
$ cp -R source_directory/ destination_directory/

# Lists the contents of "destination_directory"
$ ls destination_directory


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

&lt;/div&gt;

&lt;p&gt;So what would you expect to be printed with &lt;code&gt;ls&lt;/code&gt;? Turns out the Linux GNU implementation of &lt;code&gt;cp&lt;/code&gt; copies the &lt;code&gt;source_directory&lt;/code&gt; directory to &lt;code&gt;destination_directory&lt;/code&gt;, whereas on BSD MacOS the contents are unpacked and copied, as I’d expected it to behave on both environments:&lt;/p&gt;

&lt;h3&gt;
  
  
  GNU (Linux):
&lt;/h3&gt;

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

$ ls destination_directory
source_directory


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  BSD (MacOS):
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ ls destination_directory
file1 file2


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

&lt;/div&gt;

&lt;p&gt;The trailing slash is significant in BSD, whereas the GNU implementation treats both &lt;code&gt;source_directory/&lt;/code&gt; and &lt;code&gt;source_directory&lt;/code&gt; the same. The workaround, thankfully, is really simple — append a period when you intend for the contents to be copied and you’ll see the same behavior on both BSD and GNU : &lt;code&gt;cp -R source_directory/. destination_directory/.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I hope this tidbit helps you write better cross environment code on MacOS and helps you save some time debugging unexpected results.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bash</category>
      <category>devops</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
