<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-05-09T06:38:30+00:00</updated><id>/feed.xml</id><title type="html">Aniket’s Dev Diary</title><subtitle></subtitle><author><name>Aniket Patidar</name><email>aniketpatidar01@gmail.com</email></author><entry><title type="html">Rails Performance Monitoring A Primer For Developers</title><link href="/2026/02/28/rails-performance-monitoring-a-primer-for-developers.html" rel="alternate" type="text/html" title="Rails Performance Monitoring A Primer For Developers" /><published>2026-02-28T00:00:00+00:00</published><updated>2026-02-28T00:00:00+00:00</updated><id>/2026/02/28/rails-performance-monitoring-a-primer-for-developers</id><content type="html" xml:base="/2026/02/28/rails-performance-monitoring-a-primer-for-developers.html"><![CDATA[<p>“Rails is slow.”</p>

<p>It’s a phrase many developers hear throughout their careers. However, Rails isn’t inherently slow; it becomes slow when we make expensive mistakes in our code and lack the visibility to find them. This guide breaks down a top-down approach to monitoring and fixing performance issues to ensure your application scales effectively.</p>

<h2 id="1-the-power-of-apm-application-performance-monitoring">1. The Power of APM (Application Performance Monitoring)</h2>

<p>To fix performance, you first need data. APM tools like New Relic, Datadog, or Scout APM provide vital “telemetry” data to monitor the health of your app.</p>

<h3 id="key-metrics-to-watch">Key Metrics to Watch:</h3>
<p>Request Queuing: This measures how long a request waits before being processed by your server. Ideally, this should be between 20ms and 50ms. If it’s higher, your servers are overloaded; if it’s consistently lower, you might be over-paying for hardware.</p>

<p>Top Transactions: Don’t guess what’s slow. Look at your most frequent and slowest endpoints to identify which areas of your code will provide the biggest performance gain when fixed.</p>

<p>Object Allocation: High memory usage is often caused by creating too many Ruby objects. For example, using <code class="language-plaintext highlighter-rouge">Product.all</code> on a large database will spike memory. Instead, use <code class="language-plaintext highlighter-rouge">find_each</code> to load records in small batches.</p>

<h2 id="2-profiling-and-benchmarking">2. Profiling and Benchmarking</h2>

<p>Once you know which page is slow, you need to find the specific line of code responsible.</p>

<p>Profiling: Tools like rack-mini-profiler allow you to see exactly how much time is spent on SQL queries vs. rendering directly in your browser. It provides a “backtrace” so you can link a slow query to the exact file and line in your Rails app.</p>

<p>Benchmarking: If you think a code change will make things faster, you must prove it. Using tools like Benchmark IPS (Iterations Per Second) allows you to compare the “Before” and “After” of your changes with statistical accuracy.</p>

<h2 id="3-common-performance-killers">3. Common Performance Killers</h2>

<p>Most Rails bottlenecks fall into a few predictable categories. Avoid these common mistakes:</p>

<h3 id="i-advanced-n1-queries">I. Advanced N+1 Queries</h3>
<p>We often miss N+1 queries in complex views. Watch out for:
The Count Trap: Using <code class="language-plaintext highlighter-rouge">.count</code> on an association triggers a database query every time. Use <code class="language-plaintext highlighter-rouge">.size</code> to use the data already in memory.
The Filter Trap: Using <code class="language-plaintext highlighter-rouge">.where</code> on an eager-loaded association forces a new database hit. Use Ruby’s <code class="language-plaintext highlighter-rouge">.find</code> or <code class="language-plaintext highlighter-rouge">.select</code> to filter the data in memory instead.</p>

<h3 id="ii-synchronous-external-tasks">II. Synchronous External Tasks</h3>
<p>Never make a user wait while your app talks to a third party. Tasks like sending an email, an SMS, or a WhatsApp message should always be moved to a Background Job. This keeps the user experience snappy and the server free to handle the next request.</p>

<h3 id="iii-third-party-timeouts">III. Third-Party Timeouts</h3>
<p>If you rely on an external API, never use the default timeout (which is often 60 seconds). If that service slows down, your entire app will hang. Set strict timeouts—usually around 2 seconds—to fail fast and stay in control of your app’s responsiveness.</p>

<h3 id="iv-missing-database-indexes">IV. Missing Database Indexes</h3>
<p>A missing index forces the database to scan every single row in a table (a Sequential Scan). Adding a simple index can reduce query costs from thousands to nearly zero. Use the <code class="language-plaintext highlighter-rouge">EXPLAIN</code> command to see how the database plans to run your query and identify where indexes are missing.</p>

<h2 id="summary">Summary</h2>
<p>Scaling Rails is about a disciplined, top-down approach:</p>
<ol>
  <li>Monitor with APM to find the bottleneck.</li>
  <li>Profile to find the specific line of code.</li>
  <li>Benchmark to prove your fix works.</li>
  <li>Optimize by fixing N+1s, moving tasks to background jobs, and adding database indexes.</li>
</ol>

<p>By following these steps, you can ensure your Rails application stays fast, regardless of how much traffic you receive.</p>]]></content><author><name>Aniket Patidar</name><email>aniketpatidar01@gmail.com</email></author><summary type="html"><![CDATA[“Rails is slow.”]]></summary></entry><entry><title type="html">How to Easily Add VS Code Extensions in Antigravity When Not Available on Open VSX</title><link href="/how-to-easily-add-vs-code-extensions-in-antigravity-when-not-available-on-open-vsx/" rel="alternate" type="text/html" title="How to Easily Add VS Code Extensions in Antigravity When Not Available on Open VSX" /><published>2025-11-26T00:00:00+00:00</published><updated>2025-11-26T00:00:00+00:00</updated><id>/how-to-easily-add-vs-code-extensions-in-antigravity-when-not-available-on-open-vsx</id><content type="html" xml:base="/how-to-easily-add-vs-code-extensions-in-antigravity-when-not-available-on-open-vsx/"><![CDATA[<p>I began with a simple task: installing the Chai theme extension in Antigravity.<br />
My first thought was to search for it in the editor’s extension marketplace, but nothing appeared. I tried several different keywords, but still had no success.</p>

<p>It became clear that the theme wasn’t available in the Open VSX registry, which is the only marketplace Antigravity can use by default. Due to licensing rules, Antigravity can’t access the official Microsoft marketplace, so it couldn’t download the extension automatically.</p>

<p>This left me with only one option: to install it manually.</p>

<h3 id="getting-the-vsix-file">Getting the VSIX File</h3>

<p>Since the extension wasn’t available in Open VSX, I obtained the .vsix package directly from VS Code. Once you have the VSIX file, Antigravity can easily install it locally. In my case, the file was:</p>

<p><code class="language-plaintext highlighter-rouge">hiteshchoudharycode.chai-theme-0.2.0-web.vsix</code></p>

<h3 id="installing-the-extension-manually">Installing the Extension Manually</h3>

<p>Antigravity supports the same local extension installation process as VS Code. All you need is this command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>antigravity <span class="nt">--install-extension</span> hiteshchoudharycode.chai-theme-0.2.0-web.vsix
</code></pre></div></div>

<p>Right after that, you receive the confirmation:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Installing extensions...
Extension <span class="s1">'hiteshchoudharycode.chai-theme-0.2.0-web.vsix'</span> was successfully installed.
</code></pre></div></div>

<p>Theme applied.</p>

<h3 id="final-notes">Final Notes</h3>

<p>If an extension isn’t available in Open VSX, you can always:</p>

<ol>
  <li>
    <p>Download the .vsix file</p>
  </li>
  <li>
    <p>Install it manually</p>
  </li>
</ol>

<p>This method works and saves you from having to switch editors just for a theme or plugin.</p>]]></content><author><name>Aniket Patidar</name><email>aniketpatidar01@gmail.com</email></author><summary type="html"><![CDATA[I began with a simple task: installing the Chai theme extension in Antigravity. My first thought was to search for it in the editor’s extension marketplace, but nothing appeared. I tried several different keywords, but still had no success.]]></summary></entry><entry><title type="html">NestJS REPL: Bringing Back the Rails Console Experience</title><link href="/bringing-back-the-rails-console-feeling-in-a-nestjs-prisma-world/" rel="alternate" type="text/html" title="NestJS REPL: Bringing Back the Rails Console Experience" /><published>2025-11-21T00:00:00+00:00</published><updated>2025-11-21T00:00:00+00:00</updated><id>/nestjs-bringing-back-the-rails-console-experience</id><content type="html" xml:base="/bringing-back-the-rails-console-feeling-in-a-nestjs-prisma-world/"><![CDATA[<p>If you’ve ever worked with Rails, you’re likely familiar with the console, a tool that becomes second nature for exploring models, debugging, or modifying data quickly. Transitioning to NestJS, you might miss this handy feature, as it’s not available out of the box. However, you can create your own version.</p>

<p>A straightforward approach is to use Prisma, as its client is self-contained and easily integrated into a REPL. A simple script can get you started:</p>

<div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">PrismaClient</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@prisma/client</span><span class="dl">'</span><span class="p">;</span>

<span class="k">async</span> <span class="kd">function</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">prisma</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PrismaClient</span><span class="p">();</span>
  <span class="kd">const</span> <span class="nx">repl</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">repl</span><span class="dl">'</span><span class="p">).</span><span class="nx">start</span><span class="p">(</span><span class="dl">'</span><span class="s1">&gt; </span><span class="dl">'</span><span class="p">);</span>
  <span class="nx">repl</span><span class="p">.</span><span class="nx">context</span><span class="p">.</span><span class="nx">prisma</span> <span class="o">=</span> <span class="nx">prisma</span><span class="p">;</span>
<span class="p">}</span>

<span class="nx">main</span><span class="p">();</span>
</code></pre></div></div>

<p>Place this script in a file like <code class="language-plaintext highlighter-rouge">src/repl.ts</code> and execute it:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npx ts-node src/repl.ts
</code></pre></div></div>

<p>Now, you can perform similar tasks as you would in a Rails console:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> await prisma.user.findMany<span class="o">()</span>
</code></pre></div></div>

<p>While it doesn’t load the full Rails environment, it serves its purpose.</p>

<h3 id="and-yes-prisma-studio-exists">And yes, Prisma Studio exists</h3>

<p>Before diving into building a custom REPL, consider that Prisma comes with <strong>Prisma Studio</strong>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npx prisma studio
</code></pre></div></div>

<p>Prisma Studio provides a clean interface for viewing and editing tables. It’s excellent for browsing data but doesn’t quite capture the “let me try this query right now” feel of the Rails console. This is where the REPL comes in handy.</p>

<h3 id="when-the-repl-is-the-right-choice">When the REPL is the Right Choice</h3>

<ul>
  <li>Testing a query before integrating it into a service</li>
</ul>

<p>In summary, a small REPL can be sufficient for quickly testing queries without the need to launch the entire application.</p>]]></content><author><name>Aniket Patidar</name><email>aniketpatidar01@gmail.com</email></author><summary type="html"><![CDATA[If you’ve ever worked with Rails, you’re likely familiar with the console, a tool that becomes second nature for exploring models, debugging, or modifying data quickly. Transitioning to NestJS, you might miss this handy feature, as it’s not available out of the box. However, you can create your own version.]]></summary></entry><entry><title type="html">How I contributed notifications to an open-source product</title><link href="/how-i-contributed-notifications-to-an-open-source-product/" rel="alternate" type="text/html" title="How I contributed notifications to an open-source product" /><published>2025-07-06T00:00:00+00:00</published><updated>2025-07-06T00:00:00+00:00</updated><id>/how-i-contributed-notifications-to-an-open-source-product</id><content type="html" xml:base="/how-i-contributed-notifications-to-an-open-source-product/"><![CDATA[<p>This post details my contribution to the notification system for Moneygun, an open-source, white-label SaaS boilerplate. It provides a practical and actionable guide on integrating notifications into a Rails application using the <a href="https://github.com/excid3/noticed">Noticed</a> gem.</p>

<p><a href="https://github.com/yshmarov/moneygun/pull/286">https://github.com/yshmarov/moneygun/pull/286</a><br />
First, I want to share that I learned about <a href="https://x.com/yarotheslav">Yaroslav Shmarov</a> (@yarotheslav) looking for contributors for their open-source product, Moneygun, through a Twitter post he made. I also wanted to explore the new version of the Noticed gem, so I decided to give it a try. That’s how I got the opportunity to work on this <a href="https://github.com/yshmarov/moneygun/issues/285">issue</a>.</p>

<p>Do check out Moneygun if you want to build your next B2B SaaS app (software as a service): <a href="https://github.com/yshmarov/moneygun">https://github.com/yshmarov/moneygun</a></p>

<p><a href="https://x.com/yarotheslav/status/1934196524633706540"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751806188505/251884e9-cc45-4543-a204-0a066a36b808.png align=&quot;center&quot;" alt="" /></a></p>

<p>There are two things that need to be implemented.</p>

<ul>
  <li>
    <p>In-app notifications</p>
  </li>
  <li>
    <p>Email</p>
  </li>
</ul>

<p>First, I explored the gem to understand how to implement basic boilerplate code for notifications, then began by adding the gem to the Rails application:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># notifications</span>
<span class="n">gem</span> <span class="s2">"noticed"</span>
</code></pre></div></div>

<p>Or</p>

<p>Run the following command to add Noticed to your Gemfile:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle add <span class="s2">"noticed"</span>
</code></pre></div></div>

<p>Generate and then run the migrations:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rails</span> <span class="n">noticed</span><span class="ss">:install:migrations</span>
<span class="n">rails</span> <span class="n">db</span><span class="ss">:migrate</span>
</code></pre></div></div>

<p>To start, create a Notifier:</p>

<p>We have two requirements here:</p>

<ol>
  <li>
    <p>The user should be notified when they are invited to an organization.</p>
  </li>
  <li>
    <p>The user should be notified when their membership request is accepted.</p>
  </li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails generate noticed:notifier MembershipInvitationNotifier
rails generate noticed:notifier MembershipRequestAcceptedNotifier
</code></pre></div></div>

<p>In this post, we’ll deliver notifications by email, and in the next post, we’ll cover turbo_stream, which provides real-time UI updates to users’ browsers.</p>

<p>First, let’s take a look at how the generated notifier appears.</p>

<p>Three files are created under the notifiers:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/notifiers/application_notifier.rb</span>
<span class="k">class</span> <span class="nc">ApplicationNotifier</span> <span class="o">&lt;</span> <span class="no">Noticed</span><span class="o">::</span><span class="no">Event</span>
<span class="k">end</span>
</code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/notifiers/membership_request_accepted_notifier.rb</span>
<span class="c1"># To deliver this notification:</span>
<span class="c1">#</span>
<span class="c1"># MembershipRequestAcceptedNotifier.with(record: @post, message: "New post").deliver(User.all)</span>
<span class="k">class</span> <span class="nc">MembershipRequestAcceptedNotifier</span> <span class="o">&lt;</span> <span class="no">ApplicationNotifier</span>
 <span class="c1"># Add your delivery methods</span>
 <span class="c1">#</span>
 <span class="c1"># deliver_by :email do |config|</span>
 <span class="c1">#   config.mailer = "UserMailer"</span>
 <span class="c1">#   config.method = "new_post"</span>
 <span class="c1"># end</span>
 <span class="c1">#</span>
 <span class="c1"># bulk_deliver_by :slack do |config|</span>
 <span class="c1">#   config.url = -&gt; { Rails.application.credentials.slack_webhook_url }</span>
 <span class="c1"># end</span>
 <span class="c1">#</span>
 <span class="c1"># deliver_by :custom do |config|</span>
 <span class="c1">#   config.class = "MyDeliveryMethod"</span>
 <span class="c1"># end</span>
 <span class="c1">#</span>
 <span class="c1"># Add required params</span>
 <span class="c1">#</span>
 <span class="c1"># required_param :message</span>
<span class="k">end</span>
</code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/notifiers/membership_invitation_notifier.rb</span>
<span class="c1"># To deliver this notification:</span>
<span class="c1">#</span>
<span class="c1"># MembershipInvitationNotifier.with(record: @post, message: "New post").deliver(User.all)</span>
<span class="k">class</span> <span class="nc">MembershipInvitationNotifier</span> <span class="o">&lt;</span> <span class="no">ApplicationNotifier</span>
 <span class="c1"># Add your delivery methods</span>
 <span class="c1">#</span>
 <span class="c1"># deliver_by :email do |config|</span>
 <span class="c1">#   config.mailer = "UserMailer"</span>
 <span class="c1">#   config.method = "new_post"</span>
 <span class="c1"># end</span>
 <span class="c1">#</span>
 <span class="c1"># bulk_deliver_by :slack do |config|</span>
 <span class="c1">#   config.url = -&gt; { Rails.application.credentials.slack_webhook_url }</span>
 <span class="c1"># end</span>
 <span class="c1">#</span>
 <span class="c1"># deliver_by :custom do |config|</span>
 <span class="c1">#   config.class = "MyDeliveryMethod"</span>
 <span class="c1"># end</span>
 <span class="c1">#</span>
 <span class="c1"># Add required params</span>
 <span class="c1">#</span>
 <span class="c1"># required_param :message</span>
<span class="k">end</span>
</code></pre></div></div>

<p>In the boilerplate code, you can see there’s⁣<code class="language-plaintext highlighter-rouge">deliver_by: email</code>, so we will implement the mailer delivery method first.</p>

<p>We won’t complicate things for now; we’ll start with one notifier to give you an idea, and then you can implement another notifier on your own.</p>

<p>So we need to notify the user when he is invited to an organization. First, clean up the commented lines and keep only the ones that are needed.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MembershipInvitationNotifier</span> <span class="o">&lt;</span> <span class="no">ApplicationNotifier</span>
 <span class="c1"># Add your delivery methods</span>
 <span class="c1">#</span>
 <span class="c1"># deliver_by :email do |config|</span>
 <span class="c1">#   config.mailer = "UserMailer"</span>
 <span class="c1">#   config.method = "new_post"</span>
 <span class="c1"># end</span>
 <span class="c1">#</span>
 <span class="c1"># Add required params</span>
 <span class="c1">#</span>
 <span class="c1"># required_param :message</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Notifiers can use different helper methods. Inside a notification_methods block, we also set up the message and URL helpers.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">notification_methods</span> <span class="k">do</span>
   <span class="c1"># I18n helpers</span>
   <span class="k">def</span> <span class="nf">message</span>
     <span class="n">t</span><span class="p">(</span><span class="s2">".message"</span><span class="p">)</span>
   <span class="k">end</span>

   <span class="c1"># URL helpers are accessible in notifications</span>
   <span class="c1"># Don't forget to set your default_url_options so Rails knows how to generate urls</span>
   <span class="k">def</span> <span class="nf">url</span>
     <span class="n">user_invitations_url</span>
   <span class="k">end</span>
 <span class="k">end</span>
</code></pre></div></div>

<p>These helpers can be helpful when rendering a user’s notifications on the web.</p>

<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div&gt;</span>
  <span class="cp">&lt;%</span> <span class="vi">@user</span><span class="p">.</span><span class="nf">notifications</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">notification</span><span class="o">|</span> <span class="cp">%&gt;</span>
    <span class="cp">&lt;%=</span> <span class="n">link_to</span> <span class="n">notification</span><span class="p">.</span><span class="nf">message</span><span class="p">,</span> <span class="n">notification</span><span class="p">.</span><span class="nf">url</span> <span class="cp">%&gt;</span>
  <span class="cp">&lt;%</span> <span class="k">end</span> <span class="cp">%&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>Calling the message helper in the ERB view will look for the following translation path:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># config/locales/en.yml</span>
<span class="na">en</span><span class="pi">:</span>
 <span class="na">notifiers</span><span class="pi">:</span>
   <span class="na">membership_invitation_notifier</span><span class="pi">:</span>
     <span class="na">notification</span><span class="pi">:</span>
       <span class="na">message</span><span class="pi">:</span> <span class="s">You've been invited to join %{organization_name}</span>
</code></pre></div></div>

<p>Notifiers can choose required parameters using the <code class="language-plaintext highlighter-rouge">required_params</code>method. We need to declare <code class="language-plaintext highlighter-rouge">:organization</code> as a required parameter to ensure <code class="language-plaintext highlighter-rouge">params[:organization]</code> is available in our notifier:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">required_params</span> <span class="ss">:organization</span>
</code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">def</span> <span class="nf">message</span>
   <span class="n">t</span><span class="p">(</span><span class="s2">".message"</span><span class="p">,</span> <span class="ss">organization_name: </span><span class="n">params</span><span class="p">[</span><span class="ss">:organization</span><span class="p">].</span><span class="nf">name</span><span class="p">)</span>
 <span class="k">end</span>
</code></pre></div></div>

<p>In this case, we need the mailer, so generate it by running</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails generate mailer MembershipMailer invitation_email
</code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/mailers/membership_mailer.rb</span>
<span class="k">class</span> <span class="nc">MembershipMailer</span> <span class="o">&lt;</span> <span class="no">ApplicationMailer</span>
  <span class="c1"># Subject can be set in your I18n file at config/locales/en.yml</span>
  <span class="c1"># with the following lookup:</span>
  <span class="c1">#</span>
  <span class="c1">#   en.membership_mailer.invitation_email.subject</span>
  <span class="c1">#</span>
  <span class="k">def</span> <span class="nf">invitation_email</span>
    <span class="vi">@greeting</span> <span class="o">=</span> <span class="s2">"Hi"</span>
    <span class="n">mail</span> <span class="ss">to: </span><span class="s2">"to@example.org"</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>app/views/membership_mailer/invitation_email.text.erb</p>

<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Membership#invitation_email

<span class="cp">&lt;%=</span> <span class="vi">@greeting</span> <span class="cp">%&gt;</span>, find me in app/views/membership_mailer/invitation_email.text.erb
</code></pre></div></div>

<p>Instead of using this default greeting, we want to send our message and include the action_url. To do this, we need to have the notification object available, so we should pass it from our notifier like this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">deliver_by</span> <span class="ss">:email</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">mailer</span> <span class="o">=</span> <span class="s2">"MembershipMailer"</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">method</span> <span class="o">=</span> <span class="ss">:invitation_email</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">args</span>   <span class="o">=</span> <span class="o">-&gt;</span> <span class="p">{</span> <span class="p">[</span> <span class="nb">self</span> <span class="p">]</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Now we need to make a small change to our mailer method.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/mailers/membership_mailer.rb</span>
<span class="k">class</span> <span class="nc">MembershipMailer</span> <span class="o">&lt;</span> <span class="no">ApplicationMailer</span>
  <span class="k">def</span> <span class="nf">invitation_email</span><span class="p">(</span><span class="n">notification</span><span class="p">)</span>
    <span class="n">setup</span><span class="p">(</span><span class="n">notification</span><span class="p">)</span>
    <span class="n">mail</span><span class="p">(</span><span class="ss">to: </span><span class="vi">@recipient</span><span class="p">.</span><span class="nf">email</span><span class="p">,</span> <span class="ss">subject: </span><span class="n">t</span><span class="p">(</span><span class="s2">".subject"</span><span class="p">,</span> <span class="ss">organization_name: </span><span class="vi">@organization</span><span class="p">.</span><span class="nf">name</span><span class="p">))</span>
  <span class="k">end</span>

  <span class="kp">private</span>

  <span class="k">def</span> <span class="nf">setup</span><span class="p">(</span><span class="n">notification</span><span class="p">)</span>
    <span class="vi">@organization</span> <span class="o">=</span> <span class="n">notification</span><span class="p">.</span><span class="nf">params</span><span class="p">[</span><span class="ss">:organization</span><span class="p">]</span>
    <span class="vi">@message</span> <span class="o">=</span> <span class="n">notification</span><span class="p">.</span><span class="nf">message</span>
    <span class="vi">@recipient</span> <span class="o">=</span> <span class="n">notification</span><span class="p">.</span><span class="nf">recipient</span>
    <span class="vi">@action_url</span> <span class="o">=</span> <span class="n">notification</span><span class="p">.</span><span class="nf">url</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/views/membership_mailer/invitation_email.text.erb</span>
<span class="o">&lt;</span><span class="sx">%= @message %&gt;

View your invitations: &lt;%=</span> <span class="vi">@action_url</span> <span class="o">%&gt;</span>
</code></pre></div></div>

<p>Now our notifier code looks like this:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MembershipInvitationNotifier</span> <span class="o">&lt;</span> <span class="no">ApplicationNotifier</span>
  <span class="c1"># Add your delivery methods</span>
  <span class="n">deliver_by</span> <span class="ss">:email</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
    <span class="n">config</span><span class="p">.</span><span class="nf">mailer</span> <span class="o">=</span> <span class="s2">"MembershipMailer"</span>
    <span class="n">config</span><span class="p">.</span><span class="nf">method</span> <span class="o">=</span> <span class="ss">:invitation_email</span>
    <span class="n">config</span><span class="p">.</span><span class="nf">args</span>   <span class="o">=</span> <span class="o">-&gt;</span> <span class="p">{</span> <span class="p">[</span> <span class="nb">self</span> <span class="p">]</span> <span class="p">}</span>
  <span class="k">end</span>

  <span class="c1"># Add required params</span>
  <span class="n">required_params</span> <span class="ss">:organization</span>

  <span class="n">notification_methods</span> <span class="k">do</span>
    <span class="c1"># I18n helpers</span>
    <span class="k">def</span> <span class="nf">message</span>
      <span class="n">t</span><span class="p">(</span><span class="s2">".message"</span><span class="p">,</span> <span class="ss">organization_name: </span><span class="n">params</span><span class="p">[</span><span class="ss">:organization</span><span class="p">].</span><span class="nf">name</span><span class="p">)</span>
    <span class="k">end</span>

    <span class="c1"># URL helpers are accessible in notifications</span>
    <span class="c1"># Don't forget to set your default_url_options so Rails knows how to generate urls</span>
    <span class="k">def</span> <span class="nf">url</span>
      <span class="n">user_invitations_url</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Our notifier setup is now complete. Next, we need to trigger this notifier:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/models/membership.rb</span>
<span class="k">class</span> <span class="nc">Membership</span> <span class="o">&lt;</span> <span class="no">ApplicationRecord</span>
  <span class="n">after_create</span> <span class="ss">:send_invitation_notification</span>

  <span class="kp">private</span>

  <span class="k">def</span> <span class="nf">send_invitation_notification</span>
    <span class="no">MembershipInvitationNotifier</span><span class="p">.</span><span class="nf">with</span><span class="p">(</span><span class="ss">organization: </span><span class="n">organization</span><span class="p">).</span><span class="nf">deliver</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>With this setup in place, we have everything necessary to notify a user when they are invited to join an organization. Thank you for taking the time to read.</p>]]></content><author><name>Aniket Patidar</name><email>aniketpatidar01@gmail.com</email></author><category term="opensource," /><category term="ruby-on-rails," /><category term="notifications" /><summary type="html"><![CDATA[This post details my contribution to the notification system for Moneygun, an open-source, white-label SaaS boilerplate. It provides a practical and actionable guide on integrating notifications into a Rails application using the Noticed gem.]]></summary></entry><entry><title type="html">Setting Up asdf to Manage Node.js and Ruby on Ubuntu</title><link href="/setting-up-asdf-to-manage-nodejs-and-ruby-on-ubuntu/" rel="alternate" type="text/html" title="Setting Up asdf to Manage Node.js and Ruby on Ubuntu" /><published>2025-03-25T00:00:00+00:00</published><updated>2025-03-25T00:00:00+00:00</updated><id>/setting-up-asdf-to-manage-nodejs-and-ruby-on-ubuntu</id><content type="html" xml:base="/setting-up-asdf-to-manage-nodejs-and-ruby-on-ubuntu/"><![CDATA[<p>Managing multiple versions of programming languages can be a headache, but asdf simplifies this process by providing a single CLI tool to manage versions of multiple runtime languages. In this article, we’ll walk through the steps to install and configure asdf on Ubuntu, along with Node.js and Ruby.</p>

<h2 id="prerequisites">Prerequisites</h2>

<p>Before we begin, ensure that you have <code class="language-plaintext highlighter-rouge">curl</code> and <code class="language-plaintext highlighter-rouge">git</code> installed on your system. You can install them using the following command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>curl git
</code></pre></div></div>

<h2 id="step-1-clone-the-asdf-repository">Step 1: Clone the asdf Repository</h2>

<p>First, clone the asdf repository from GitHub into your home directory:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/asdf-vm/asdf.git ~/.asdf <span class="nt">--branch</span> v0.14.0
</code></pre></div></div>

<p>This command checks out the version 0.14.0 of asdf. Adjust the version number as needed.</p>

<h2 id="step-2-update-your-shell-configuration">Step 2: Update Your Shell Configuration</h2>

<p>To make asdf available in your terminal, you need to update your shell configuration. Add the following lines to your <code class="language-plaintext highlighter-rouge">~/.bashrc</code> file:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> <span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.asdf/asdf.sh"</span>
<span class="nb">.</span> <span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.asdf/completions/asdf.bash"</span>
</code></pre></div></div>

<p>After adding these lines, reload your <code class="language-plaintext highlighter-rouge">~/.bashrc</code> file to apply the changes:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">source</span> ~/.bashrc
</code></pre></div></div>

<h2 id="step-3-install-nodejs">Step 3: Install Node.js</h2>

<p>To install Node.js using asdf, follow these steps:</p>

<h3 id="install-additional-dependencies">Install Additional Dependencies</h3>

<p>Node.js requires some additional dependencies which can be installed using the following command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt-get <span class="nb">install </span>dirmngr gpg curl gawk
</code></pre></div></div>

<h3 id="add-the-nodejs-plugin">Add the Node.js Plugin</h3>

<p>Next, add the Node.js plugin to asdf:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
</code></pre></div></div>

<h3 id="install-the-latest-version-of-nodejs">Install the Latest Version of Node.js</h3>

<p>You can now install the latest version of Node.js:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>asdf <span class="nb">install </span>nodejs latest
</code></pre></div></div>

<h2 id="step-4-install-ruby">Step 4: Install Ruby</h2>

<p>To install Ruby using asdf, follow these steps:</p>

<h3 id="add-the-ruby-plugin">Add the Ruby Plugin</h3>

<p>First, add the Ruby plugin to asdf:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>asdf plugin add ruby https://github.com/asdf-vm/asdf-ruby.git
</code></pre></div></div>

<h3 id="install-the-latest-version-of-ruby">Install the Latest Version of Ruby</h3>

<p>Now, you can install the latest version of Ruby:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>asdf <span class="nb">install </span>ruby latest
</code></pre></div></div>

<h2 id="step-5-verify-the-installation">Step 5: Verify the Installation</h2>

<p>It’s important to verify that asdf has correctly installed and configured the runtime versions. You can do this by checking the output of the <code class="language-plaintext highlighter-rouge">type -a ruby</code> command.</p>

<ul>
  <li>
    <p><strong>Correct Output:</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  ruby is /home/username/.asdf/shims/ruby
  ruby is /usr/bin/ruby
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Incorrect Output:</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  ruby is /usr/bin/ruby
</code></pre></div>    </div>
  </li>
</ul>

<p>If you see the correct output, it means that asdf is correctly managing the Ruby version.</p>

<h2 id="conclusion">Conclusion</h2>

<p>By following these steps, you’ve installed asdf and configured it to manage Node.js and Ruby on your system. This setup will help you seamlessly switch between different versions of these runtimes, making your development environment more flexible and efficient.</p>]]></content><author><name>Aniket Patidar</name><email>aniketpatidar01@gmail.com</email></author><summary type="html"><![CDATA[Managing multiple versions of programming languages can be a headache, but asdf simplifies this process by providing a single CLI tool to manage versions of multiple runtime languages. In this article, we’ll walk through the steps to install and configure asdf on Ubuntu, along with Node.js and Ruby.]]></summary></entry><entry><title type="html">Understanding Getter and Setter Methods in Ruby!</title><link href="/understanding-getter-and-setter-methods-in-ruby/" rel="alternate" type="text/html" title="Understanding Getter and Setter Methods in Ruby!" /><published>2025-03-25T00:00:00+00:00</published><updated>2025-03-25T00:00:00+00:00</updated><id>/understanding-getter-and-setter-methods-in-ruby</id><content type="html" xml:base="/understanding-getter-and-setter-methods-in-ruby/"><![CDATA[<p>Getter and setter methods in Ruby provide a controlled way to access and modify the values of instance variables from outside the class. This helps maintain data integrity and adheres to the principle of encapsulation, which means hiding the internal state of an object and only exposing necessary parts.</p>

<h2 id="what">What?</h2>

<ul>
  <li><strong>Getter Methods</strong>: Allow reading the value of an instance variable.</li>
  <li><strong>Setter Methods</strong>: Allow modifying the value of an instance variable.</li>
</ul>

<h2 id="how">How?</h2>

<p>Ruby simplifies the creation of these methods with <code class="language-plaintext highlighter-rouge">attr_accessor</code>, <code class="language-plaintext highlighter-rouge">attr_reader</code>, and <code class="language-plaintext highlighter-rouge">attr_writer</code>.</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">attr_reader</code>: Generates only getter methods.</li>
  <li><code class="language-plaintext highlighter-rouge">attr_writer</code>: Generates only setter methods.</li>
  <li><code class="language-plaintext highlighter-rouge">attr_accessor</code>: Generates both getter and setter methods.</li>
</ul>

<h3 id="example">Example</h3>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Product</span>
  <span class="nb">attr_reader</span> <span class="ss">:name</span>     <span class="c1"># Generates only a getter for `name`</span>
  <span class="nb">attr_writer</span> <span class="ss">:price</span>    <span class="c1"># Generates only a setter for `price`</span>
  <span class="nb">attr_accessor</span> <span class="ss">:stock</span>  <span class="c1"># Generates both getter and setter for `stock`</span>

  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="n">stock</span><span class="p">)</span>
    <span class="vi">@name</span> <span class="o">=</span> <span class="nb">name</span>
    <span class="vi">@price</span> <span class="o">=</span> <span class="n">price</span>
    <span class="vi">@stock</span> <span class="o">=</span> <span class="n">stock</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="n">product</span> <span class="o">=</span> <span class="no">Product</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"T-Shirt"</span><span class="p">,</span> <span class="mf">19.99</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
<span class="nb">puts</span> <span class="n">product</span><span class="p">.</span><span class="nf">name</span>        <span class="c1"># Output: T-Shirt (using getter)</span>
<span class="n">product</span><span class="p">.</span><span class="nf">price</span> <span class="o">=</span> <span class="mf">24.99</span>    <span class="c1"># No getter for `price`, but setter allows modification</span>
<span class="n">product</span><span class="p">.</span><span class="nf">stock</span> <span class="o">=</span> <span class="mi">5</span>        <span class="c1"># Both getter and setter available for `stock`</span>
</code></pre></div></div>

<h2 id="listing-instance-variables-and-methods">Listing Instance Variables and Methods</h2>

<p>Ruby provides built-in methods to inspect an object’s instance variables and methods:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">#instance_variables</code>: Returns a list of instance variables.</li>
  <li><code class="language-plaintext highlighter-rouge">#public_methods</code>: Returns a list of public methods.</li>
</ul>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">p</span> <span class="n">product</span><span class="p">.</span><span class="nf">instance_variables</span>  <span class="c1"># Output: [:@name, :@price, :@stock]</span>
<span class="nb">p</span> <span class="n">product</span><span class="p">.</span><span class="nf">public_methods</span>      <span class="c1"># Output: List of public methods, including `name`, `price=`, and `stock`</span>
</code></pre></div></div>

<p>By using these tools, you can better understand the structure and capabilities of your objects.</p>]]></content><author><name>Aniket Patidar</name><email>aniketpatidar01@gmail.com</email></author><summary type="html"><![CDATA[Getter and setter methods in Ruby provide a controlled way to access and modify the values of instance variables from outside the class. This helps maintain data integrity and adheres to the principle of encapsulation, which means hiding the internal state of an object and only exposing necessary parts.]]></summary></entry></feed>