<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Lynn's Dev Blog]]></title><description><![CDATA[Lynn's Dev Blog]]></description><link>https://lynnbright.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 22:10:30 GMT</lastBuildDate><atom:link href="https://lynnbright.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Local PostgreSQL Upgrade and Database Restoration Guide]]></title><description><![CDATA[PostgreSQL Upgrade and Database Restoration Guide
To support the pgvector gem, I upgraded my local Postgres.app from v13 to v17 on macOS. Below is the full upgrade and restoration process for my project.
Environment

OS: macOS

PostgreSQL: Upgraded f...]]></description><link>https://lynnbright.com/local-postgresql-upgrade-and-database-restoration-guide</link><guid isPermaLink="true">https://lynnbright.com/local-postgresql-upgrade-and-database-restoration-guide</guid><category><![CDATA[PostgreSQL]]></category><category><![CDATA[postgres.app]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Fri, 20 Jun 2025 05:55:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/avzaiz3QKCY/upload/d886b39011da38852d93433e8fc0afa5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-postgresql-upgrade-and-database-restoration-guide"><strong>PostgreSQL Upgrade and Database Restoration Guide</strong></h3>
<p>To support the <a target="_blank" href="https://github.com/pgvector/pgvector?tab=readme-ov-file"><code>pgvector</code> gem</a>, I upgraded my local <a target="_blank" href="http://Postgres.app">Postgres.app</a> from v13 to v17 on macOS. Below is the full upgrade and restoration process for my project.</p>
<h4 id="heading-environment"><strong>Environment</strong></h4>
<ul>
<li><p><strong>OS</strong>: macOS</p>
</li>
<li><p><strong>PostgreSQL</strong>: Upgraded from v13 to v17 via <a target="_blank" href="https://postgresapp.com/">Postgres.app</a></p>
</li>
<li><p><strong>Rails</strong>: Used for database management</p>
</li>
<li><p><strong>Databases</strong>: <code>my_database_name_development</code>, <code>my_database_name_test</code></p>
</li>
</ul>
<hr />
<h3 id="heading-steps"><strong>Steps</strong></h3>
<ol>
<li><p><strong>Back Up All Databases</strong><br /> Export all databases to a single SQL file:</p>
<pre><code class="lang-bash"> pg_dumpall &gt; ~/Desktop/db_backup.sql
</code></pre>
</li>
<li><p><strong>Split the Backup File</strong><br /> Extract specific databases from the full backup:</p>
<pre><code class="lang-bash"> <span class="hljs-comment"># Development</span>
 awk <span class="hljs-string">'/^\\connect my_database_name_development/{flag=1;next} /^\\connect/{flag=0} flag'</span> ~/Desktop/db_backup.sql &gt; ~/Desktop/my_database_name_development_only.sql

 <span class="hljs-comment"># Test</span>
 awk <span class="hljs-string">'/^\\connect my_database_name_test/{flag=1;next} /^\\connect/{flag=0} flag'</span> ~/Desktop/db_backup.sql &gt; ~/Desktop/my_database_name_test_only.sql
</code></pre>
</li>
<li><p><strong>Create New Databases</strong><br /> Recreate the databases using Rails:</p>
<pre><code class="lang-bash"> rails db:create
</code></pre>
</li>
<li><p><strong>Restore Data into Databases</strong><br /> Import the split SQL files into the respective databases:</p>
<pre><code class="lang-bash"> <span class="hljs-comment"># Development</span>
 psql -d my_database_name_development -f ~/Desktop/my_database_name_development_only.sql

 <span class="hljs-comment"># Test</span>
 psql -d my_database_name_test -f ~/Desktop/my_database_name_test_only.sql
</code></pre>
</li>
</ol>
<hr />
<p>This process ensures a clean PostgreSQL upgrade while preserving all development and test data.</p>
]]></content:encoded></item><item><title><![CDATA[Resolving Rails Runtime Errors: A Guide to Handling Unpersisted Changes with with_lock]]></title><description><![CDATA[Introduction
In Ruby on Rails applications, handling database transactions efficiently is crucial to maintaining data integrity. One common issue developers face is dealing with runtime errors caused by unpersisted changes when using the with_lock me...]]></description><link>https://lynnbright.com/resolving-rails-runtime-errors-a-guide-to-handling-unpersisted-changes-with-withlock</link><guid isPermaLink="true">https://lynnbright.com/resolving-rails-runtime-errors-a-guide-to-handling-unpersisted-changes-with-withlock</guid><category><![CDATA[Rails]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Mon, 13 Jan 2025 06:27:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/roffILQTPZs/upload/4c45d887694a20749f771f130266d058.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction"><strong>Introduction</strong></h2>
<p>In Ruby on Rails applications, handling database transactions efficiently is crucial to maintaining data integrity. One common issue developers face is dealing with runtime errors caused by unpersisted changes when using the <code>with_lock</code> method. This guide will help you understand and resolve these errors effectively.</p>
<h2 id="heading-environment">Environment</h2>
<ul>
<li><p>Ruby 3.0.7</p>
</li>
<li><p>Rails 6.1.7.7</p>
</li>
</ul>
<h2 id="heading-error-message">Error message</h2>
<pre><code class="lang-ruby"><span class="hljs-symbol">RunTimeError:</span> Locking a record with unpersisted changes is <span class="hljs-keyword">not</span> supported. 
Use save to persist the changes, <span class="hljs-keyword">or</span> reload to discard them explicitly.
</code></pre>
<p><em>RunTimeError: Locking a record with unpersisted changes is not supported. Use save to persist the changes, or reload to discard them explicitly.</em></p>
<h2 id="heading-how-to-reproduce">How to Reproduce</h2>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Invoice</span> &lt; ApplicationRecord</span>
  before_save <span class="hljs-symbol">:sync_monetary_columns</span>

  <span class="hljs-comment"># Existing code...</span>

  private

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sync_monetary_columns</span></span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> amount_changed?

    with_lock <span class="hljs-keyword">do</span> 
      <span class="hljs-keyword">self</span>.amount_decimal = amount.to_f
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<pre><code class="lang-ruby">invoice = Invoice.last
invoice.amount <span class="hljs-comment"># 1000</span>

invoice.amount = <span class="hljs-number">500</span>
invoice.save!
<span class="hljs-comment"># RuntimeError: Locking a record with unpersisted changes is not supported. </span>
<span class="hljs-comment"># Use `save` to persist the changes, or `reload` to discard them explicitly.</span>
</code></pre>
<h2 id="heading-understanding-how-withlockhttpsapirubyonrailsorgclassesactiverecordlockingpessimistichtmlmethod-i-withlock-works">Understanding how <a target="_blank" href="https://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html#method-i-with_lock"><code>with_lock</code></a> Works</h2>
<p><code>with_lock</code> is a Rails method that provides pessimistic locking, which is a database-level lock that prevents multiple processes from modifying the same record simultaneously. Here's how it works:</p>
<ol>
<li><p>When <code>with_lock</code> is called, Rails:</p>
<ul>
<li><p>Starts a database transaction</p>
</li>
<li><p>Reloads the record with <code>SELECT ... FOR UPDATE</code></p>
</li>
<li><p>Executes your block of code</p>
</li>
<li><p>Commits the transaction</p>
</li>
</ul>
</li>
<li><p>The <code>FOR UPDATE</code> lock means:</p>
<ul>
<li><p>Other transactions must wait to read or modify this record</p>
</li>
<li><p>Prevents race conditions where multiple processes might try to update the same data</p>
</li>
<li><p>Lock is held until the transaction commits or rolls back</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-ruby"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">with_lock</span></span>
  transaction <span class="hljs-keyword">do</span>
    <span class="hljs-comment"># Reloads the object and obtains lock:</span>
    <span class="hljs-keyword">self</span>.reload(<span class="hljs-symbol">lock:</span> <span class="hljs-literal">true</span>)  <span class="hljs-comment"># SELECT * FROM table WHERE id = 123 FOR UPDATE</span>

    <span class="hljs-comment"># Now yields to your block:</span>
    <span class="hljs-keyword">yield</span>

    <span class="hljs-comment"># Transaction commits after your block completes</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h2 id="heading-how-to-fix-this-error">How to Fix This Error</h2>
<p>To fix the runtime error caused by unpersisted changes, here’s my key implementation details:</p>
<ol>
<li><p>Cache Values Before <code>with_lock</code>:</p>
<ul>
<li><p><code>with_lock</code> internally calls <code>reload</code>, which would clear any unpersisted changes. (Source code from <a target="_blank" href="https://github.com/rails/rails/blob/cf6ff17e9a3c6c1139040b519a341f55f0be16cf/activerecord/lib/active_record/locking/pessimistic.rb#L69">Rails</a>)</p>
</li>
<li><p>Caching preserves the values we need to modify.</p>
</li>
</ul>
</li>
<li><p>Reload Only Persisted Records:</p>
<ul>
<li><p>For persisted records: <code>with_lock</code> executes <code>reload(lock: true)</code> using the record's ID. When a record has unpersisted changes, this causes the RuntimeError.</p>
</li>
<li><p>For new records: No ID exists yet, so <code>reload</code> cannot trigger the error.</p>
</li>
</ul>
</li>
</ol>
<p>This solution ensures proper handling of both new and persisted records while maintaining data integrity during the locking process.</p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Invoice</span> &lt; ApplicationRecord</span>
  before_save <span class="hljs-symbol">:sync_monetary_columns</span>

  <span class="hljs-comment"># Existing code...</span>

  private

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sync_monetary_columns</span></span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">unless</span> amount_changed?

    <span class="hljs-comment"># Cache values </span>
    new_amount = amount.to_of

    reload <span class="hljs-keyword">if</span> persisted?

    with_lock <span class="hljs-keyword">do</span> 
      <span class="hljs-keyword">self</span>.amount_decimal = new_amount
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By understanding the mechanics of <code>with_lock</code> and implementing the suggested solutions, you can effectively manage runtime errors related to unpersisted changes in your Rails applications. This approach not only resolves the issue but also enhances the robustness of your data handling processes.</p>
<hr />
<h2 id="heading-reference">Reference</h2>
<ul>
<li><a target="_blank" href="https://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html#method-i-with_lock"><strong>Rails</strong> <code>with_lock</code> Documentation</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Upgrade to Ruby 3.0.6  (OpenSSL issues)]]></title><description><![CDATA[Environment

MacOS Sonoma 14.3

Original Ruby version: 2.7.8

Ruby Version Manager: RVM 1.29.12


Goal
Upgrade Ruby from 2.7.8 to 3.0.6.
Issues Description
After successfully installing Ruby 3.0.6, I encountered difficulties running bundle install in...]]></description><link>https://lynnbright.com/upgrade-to-ruby-306-openssl-issues</link><guid isPermaLink="true">https://lynnbright.com/upgrade-to-ruby-306-openssl-issues</guid><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Mon, 11 Mar 2024 09:29:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/hBuwVLcYTnA/upload/2582207cedca8b94096dbf40c02c8c82.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-environment">Environment</h4>
<ul>
<li><p>MacOS Sonoma 14.3</p>
</li>
<li><p>Original Ruby version: 2.7.8</p>
</li>
<li><p>Ruby Version Manager: RVM 1.29.12</p>
</li>
</ul>
<h4 id="heading-goal">Goal</h4>
<p>Upgrade Ruby from 2.7.8 to 3.0.6.</p>
<h3 id="heading-issues-description">Issues Description</h3>
<p>After successfully installing Ruby 3.0.6, I encountered difficulties running <code>bundle install</code> in my Rails project due to two OpenSSL-related issues.</p>
<ol>
<li><p>Could not load OpenSSL.</p>
</li>
<li><p><code>Bundler::Fetcher::CertificateFailureError</code></p>
</li>
</ol>
<h3 id="heading-issue-1-could-not-load-openssl">Issue 1: Could not load OpenSSL.</h3>
<pre><code class="lang-ruby">bundle install
<span class="hljs-comment"># Bundler (2.2.33) is older than the version that created the lockfile (2.3.7). We suggest you to upgrade to the version that created the lockfile by running gem install bundler:2.3.7.</span>

Could <span class="hljs-keyword">not</span> load OpenSSL.
You must recompile Ruby with OpenSSL support <span class="hljs-keyword">or</span> change the sources <span class="hljs-keyword">in</span> your Gemfile from <span class="hljs-string">'https'</span> to <span class="hljs-string">'http'</span>. Instructions <span class="hljs-keyword">for</span> compiling with OpenSSL using RVM are available at rvm.io/packages/openssl.
</code></pre>
<h4 id="heading-solution"><strong>Solution</strong></h4>
<p>If you're using macOS and RVM, here's how you can recompile Ruby with OpenSSL support:</p>
<p>1. Install the required dependencies: This is a more general command for installing openssl library on your system, potentially for use by various applications beyond Ruby.</p>
<pre><code class="lang-bash">brew install openssl
</code></pre>
<p>2. Install OpenSSL using RVM: This is specific to managing OpenSSL for Ruby installations through rvm.</p>
<pre><code class="lang-bash">rvm pkg install openssl
</code></pre>
<p>3. Install Ruby with OpenSSL support: This is use for reinstalling the required Ruby version and specify the installation location of OpenSSL.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Replace &lt;your_version&gt; with your Ruby version.</span>
rvm reinstall ruby-&lt;your_version&gt; --with-openssl-dir=$(brew --prefix openssl)
</code></pre>
<p>4. After the installation is complete, set the new Ruby version as the default:</p>
<pre><code class="lang-ruby">rvm use &lt;your_version&gt; --default
</code></pre>
<p>5. Replace <code>&lt;your_version&gt;</code> with the version you installed.</p>
<p>Check if OpenSSL is linked correctly:</p>
<pre><code class="lang-ruby">ruby -r openssl -e <span class="hljs-string">"puts OpenSSL::OPENSSL_LIBRARY_VERSION"</span>
<span class="hljs-comment">#=&gt; OpenSSL 1.0.1i 6 Aug 2014</span>
</code></pre>
<p>This should output the OpenSSL version like above, confirming that Ruby is now compiled with OpenSSL support.</p>
<p>These steps should help you resolve the OpenSSL-related issue on macOS with RVM.</p>
<h3 id="heading-issue-2-bundlerfetchercertificatefailureerror">Issue 2: Bundler::Fetcher::CertificateFailureError</h3>
<p>After resolving the OpenSSL loading issue for the Ruby process, I attempted to run <code>bundle install</code> again. However, a new error surfaced.</p>
<pre><code class="lang-bash">Fetching gem metadata from https://rubygems.org/.......
Fetching https://github.com/kaikhq/omniauth-line.git
Fetching https://github.com/banister/binding_of_caller.git
Fetching https://github.com/excid3/convertkit-ruby.git
Fetching <span class="hljs-built_in">source</span> index from https://gems.graphql.pro/

Retrying fetcher due to error (2/4): Bundler::Fetcher::CertificateFailureError Could not verify the SSL certificate <span class="hljs-keyword">for</span> https://gems.graphql.pro/.
There is a chance you are experiencing a man-in-the-middle attack, but most likely your system doesn<span class="hljs-string">'t have the CA certificates needed for verification. For information about OpenSSL certificates, see https://railsapps.github.io/openssl-certificate-verify-failed.html. To connect without using SSL, edit your Gemfile sources and change '</span>https<span class="hljs-string">' to '</span>http<span class="hljs-string">'.

Retrying fetcher due to error (3/4): Bundler::Fetcher::CertificateFailureError Could not verify the SSL certificate for https://gems.graphql.pro/.
There is a chance you are experiencing a man-in-the-middle attack, but most likely your system doesn'</span>t have the CA certificates needed <span class="hljs-keyword">for</span> verification. For information about OpenSSL certificates, see https://railsapps.github.io/openssl-certificate-verify-failed.html. To connect without using SSL, edit your Gemfile sources and change <span class="hljs-string">'https'</span> to <span class="hljs-string">'http'</span>.

Retrying fetcher due to error (4/4): Bundler::Fetcher::CertificateFailureError Could not verify the SSL certificate <span class="hljs-keyword">for</span> https://gems.graphql.pro/.
There is a chance you are experiencing a man-in-the-middle attack, but most likely your system doesn<span class="hljs-string">'t have the CA certificates needed for verification. For information about OpenSSL certificates, see https://railsapps.github.io/openssl-certificate-verify-failed.html. To connect without using SSL, edit your Gemfile sources and change '</span>https<span class="hljs-string">' to '</span>http<span class="hljs-string">'.

Could not verify the SSL certificate for https://gems.graphql.pro/.
There is a chance you are experiencing a man-in-the-middle attack, but most likely your system doesn'</span>t have the CA certificates needed <span class="hljs-keyword">for</span> verification. For information about OpenSSL certificates, see https://railsapps.github.io/openssl-certificate-verify-failed.html. To
connect without using SSL, edit your Gemfile sources and change <span class="hljs-string">'https'</span> to <span class="hljs-string">'http'</span>.
</code></pre>
<h4 id="heading-solution-1"><strong>Solution</strong></h4>
<p>This was caused by "root certificate expiration" issue（Many thanks to <a target="_blank" href="https://github.com/rubygems/rubygems/issues/4555#issuecomment-933369147">santoshcop for providing this command</a>.）. You can run the command below and run <code>bundle install</code> again. The issue will be possible to be solved.</p>
<pre><code class="lang-bash">bundle config ssl_verify_mode 0 &amp;&amp; <span class="hljs-built_in">echo</span> <span class="hljs-string">":ssl_verify_mode: 0"</span> &gt; ~/.gemrc
</code></pre>
<p>This command is used to configure Bundler to set the SSL verification mode to 0, effectively turning off SSL certificate verification. Additionally, it writes a configuration file (~/.gemrc) that includes the SSL verification mode setting, making it persistent for future gem-related operations in the user's environment.</p>
<p>To lessen security risks, I turned on SSL certificate verification after resolving this issue.</p>
<pre><code class="lang-bash">bundle config ssl_verify_mode 1 &amp;&amp; <span class="hljs-built_in">echo</span> <span class="hljs-string">":ssl_verify_mode: 1"</span> &gt; ~/.gemrc
</code></pre>
<p>Make sure the settings are configured.</p>
<pre><code class="lang-bash">bundle config ssl_verify_mode

Settings <span class="hljs-keyword">for</span> `ssl_verify_mode` <span class="hljs-keyword">in</span> order of priority. The top value will be used
Set <span class="hljs-keyword">for</span> your <span class="hljs-built_in">local</span> app (/Users/lynnbright/code/blog/.bundle/config): 1
</code></pre>
]]></content:encoded></item><item><title><![CDATA[What’s the relationship between require, $LOAD_PATH and $LOADED_FEATURES in Ruby?]]></title><description><![CDATA[It is common to see require 'something' in a Rails application. But what exactly does require do?
What is require used for in Ruby?
require is used to load external libraries or modules into your program. For example,
Before you require the JSON modu...]]></description><link>https://lynnbright.com/whats-the-relationship-between-require-loadpath-and-loadedfeatures-in-ruby</link><guid isPermaLink="true">https://lynnbright.com/whats-the-relationship-between-require-loadpath-and-loadedfeatures-in-ruby</guid><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Tue, 13 Feb 2024 08:05:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/POecJARFtAc/upload/7fffdce9801a68a4ec0536d42929e8b2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It is common to see <code>require 'something'</code> in a Rails application. But what exactly does <code>require</code> do?</p>
<h2 id="heading-what-is-require-used-for-in-ruby">What is <code>require</code> used for in Ruby?</h2>
<p><code>require</code> is used to load external libraries or modules into your program. For example,</p>
<p>Before you <code>require</code> the <code>JSON</code> module</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># in irb</span>

JSON
<span class="hljs-comment">#=&gt; Traceback (most recent call last):</span>
        <span class="hljs-number">4</span>: from /Users/lynnbright/.rvm/rubies/ruby-<span class="hljs-number">2.7</span>.<span class="hljs-number">8</span>/bin/<span class="hljs-symbol">irb:</span><span class="hljs-number">23</span><span class="hljs-symbol">:in</span> <span class="hljs-string">`&lt;main&gt;'
        3: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/bin/irb:23:in `</span>load<span class="hljs-string">'
        2: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `&lt;top (required)&gt;'</span>
        <span class="hljs-number">1</span>: from (irb)<span class="hljs-symbol">:</span><span class="hljs-number">3</span>
NameError (uninitialized constant JSON)
</code></pre>
<p>After you <code>require</code> the <code>JSON</code> module</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># in irb</span>

<span class="hljs-keyword">require</span> <span class="hljs-string">'JSON'</span>
<span class="hljs-comment">#=&gt; true</span>

JSON
<span class="hljs-comment">#=&gt; JSON</span>

data = <span class="hljs-string">'{"name": "John", "age": 30}'</span>
<span class="hljs-comment">#=&gt; =&gt; "{\"name\": \"John\", \"age\": 30}"</span>

JSON.parse(data)
<span class="hljs-comment">#=&gt; {"name"=&gt;"John", "age"=&gt;30}</span>
</code></pre>
<h2 id="heading-whats-the-relationship-between-require-loadpath-and-loadedfeatures-in-ruby">What’s the relationship between <code>require</code>, <code>$LOAD_PATH</code> and <code>$LOADED_FEATURES</code> in Ruby?</h2>
<p>Before the file is loaded, there are some steps that Ruby will do.</p>
<p>First, when we use <code>require</code>, it means that we ask Ruby to load the file. However, it is needless to load the same file again and again, right? This is how the <code>$LOAD_PATH</code> and <code>$LOADED_FEATURES</code> play important roles.</p>
<ul>
<li><p><code>$LOAD_PATH</code>: It is a global variable used to locate the file.</p>
</li>
<li><p><code>$LOADED_FEATURES</code>: It is a global variable, too. It’s used to keep tracking of which files have been loaded successfully using <code>require</code>.</p>
</li>
</ul>
<h3 id="heading-search-for-the-file">Search for the file</h3>
<p>When <code>require</code> is called, Ruby looks for a specific file from <code>$LOAD_PATH</code> which contains an array of directories.</p>
<p>If the file is found, Ruby loads and executes it.</p>
<p>If the file is not found listed in the <code>$LOAD_PATH</code>, <code>LoadError</code> is raised.</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># in irb</span>

<span class="hljs-keyword">require</span> <span class="hljs-string">'abc'</span>

<span class="hljs-comment">#=&gt; Traceback (most recent call last):</span>
        <span class="hljs-number">6</span>: from /Users/lynnbright/.rvm/rubies/ruby-<span class="hljs-number">2.7</span>.<span class="hljs-number">8</span>/bin/<span class="hljs-symbol">irb:</span><span class="hljs-number">23</span><span class="hljs-symbol">:in</span> <span class="hljs-string">`&lt;main&gt;'
        5: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/bin/irb:23:in `</span>load<span class="hljs-string">'
        4: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `&lt;top (required)&gt;'</span>
        <span class="hljs-number">3</span>: from (irb)<span class="hljs-symbol">:</span><span class="hljs-number">9</span>
        <span class="hljs-number">2</span>: from /Users/lynnbright/.rvm/rubies/ruby-<span class="hljs-number">2.7</span>.<span class="hljs-number">8</span>/lib/ruby/<span class="hljs-number">2.7</span>.<span class="hljs-number">0</span>/rubygems/core_ext/kernel_require.<span class="hljs-symbol">rb:</span><span class="hljs-number">83</span><span class="hljs-symbol">:in</span> <span class="hljs-string">`require'
        1: from /Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:83:in `</span><span class="hljs-keyword">require</span><span class="hljs-string">'
LoadError (cannot load such file -- abc)</span>
</code></pre>
<h3 id="heading-check-if-the-file-already-loaded">Check if the file already loaded:</h3>
<p>If the file is found, before actually loading it, Ruby uses <code>$LOADED_FEATURES</code>, which contains an array of files, to check if the file is already included in the array.</p>
<p>If it is included in the array, that means the file has been loaded. If not, it will be added to <code>$LOADED_FEATURES</code> to prevent it from loaded again.</p>
<h3 id="heading-lets-see-a-real-example">Let’s see a real example.</h3>
<pre><code class="lang-ruby"><span class="hljs-comment"># in irb</span>

$LOAD_PATH
<span class="hljs-comment">#=&gt; ["/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/timeout-0.4.1/lib", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby/2.7.0/x86_64-darwin21", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby/2.7.0/x86_64-darwin21", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/x86_64-darwin21"]</span>

$LOADED_FEATURES
<span class="hljs-comment">#=&gt; ["enumerator.so", "thread.rb", "rational.so", "complex.so",....]</span>

$LOADED_FEATURES.length
<span class="hljs-comment">#=&gt; 171</span>

<span class="hljs-keyword">require</span> <span class="hljs-string">'json'</span>
<span class="hljs-comment">#=&gt; true</span>

<span class="hljs-comment"># You can see that the "json" directory has been included into the $LOAD_PATH.</span>
$LOAD_PATH
<span class="hljs-comment">#=&gt; ["/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/timeout-0.4.1/lib", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/extensions/x86_64-darwin-21/2.7.0/json-2.7.1", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby/2.7.0/x86_64-darwin21", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/site_ruby", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby/2.7.0/x86_64-darwin21", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/vendor_ruby", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/x86_64-darwin21"]</span>

<span class="hljs-comment"># The array elements increased from 171 to 180, indicating that new elements have been added.</span>
$LOADED_FEATURES.length
<span class="hljs-comment">#=&gt; 180</span>

$LOADED_FEATURES
<span class="hljs-comment">#=&gt; [...., "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/version.rb", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/ostruct/version.rb", "/Users/lynnbright/.rvm/rubies/ruby-2.7.8/lib/ruby/2.7.0/ostruct.rb", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/generic_object.rb", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/common.rb", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/ext/parser.bundle", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/ext/generator.bundle", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json/ext.rb", "/Users/lynnbright/.rvm/gems/ruby-2.7.8/gems/json-2.7.1/lib/json.rb"]</span>

<span class="hljs-comment"># Attempting to require 'json' again returns false because it is already included in $LOADED_FEATURES.</span>
<span class="hljs-keyword">require</span> <span class="hljs-string">'json'</span>
<span class="hljs-comment">#=&gt; false</span>
</code></pre>
<p>In summary:</p>
<ul>
<li><p><code>require</code> is used to load the specific file.</p>
</li>
<li><p><code>$LOAD_PATH</code> is used to locate where the file is.</p>
</li>
<li><p><code>$LOADED_FEATURES</code> is used to keep tracking of which files have been loaded successfully using <code>require</code>.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How I learned to write raw SQL]]></title><description><![CDATA[In my daily job, I mainly use Rails framework. To make code readable and maintainable, we seldom write raw SQL in the codebase. Instead, we use Rails's ActiveRecord::QueryMethods module which helps developers write beautiful queries quickly. For exam...]]></description><link>https://lynnbright.com/how-i-learned-to-write-raw-sql</link><guid isPermaLink="true">https://lynnbright.com/how-i-learned-to-write-raw-sql</guid><category><![CDATA[SQL]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Thu, 25 Aug 2022 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/KYVktImsC4Q/upload/9dd6a68d89c53398d62010ca050cc379.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my daily job, I mainly use Rails framework. To make code readable and maintainable, we seldom write raw SQL in the codebase. Instead, we use Rails's <code>ActiveRecord::QueryMethods</code> module which helps developers write beautiful queries quickly. For example,</p>
<pre><code class="lang-ruby">School.joins(<span class="hljs-symbol">:students</span>).where(<span class="hljs-string">'students.age &gt; ?'</span>, <span class="hljs-number">7</span>).limit(<span class="hljs-number">100</span>)
</code></pre>
<p>Recently, I was assigned to query different operation metrics, product metrics, and marketing metrics. Due to the diversity of these metrics, I found out that if I know what the raw SQL of the metrics is, not only can I complete the query quickly, but also I can use <code>ActiveRecord::QueryMethods</code> more efficiently.</p>
<p>Here are the 4 steps that how I practice writing raw SQL.</p>
<hr />
<h3 id="heading-1-browse-the-active-record-association-declaration">1. Browse the Active Record association declaration</h3>
<p>Each metric must derive from one or more models. In the huge codebase, we might not be familiar with every model, only when we can clearly understand the association declaration between the models do we write the correct query condition.</p>
<h3 id="heading-2-imitation-is-the-start-of-all-learning">2. Imitation is the start of all learning</h3>
<p>At first, I know how to query by Rails <code>ActiveRecord::QueryMethods</code>, but I don't know how to write the raw SQL.</p>
<p>It's OK. Rails console can help us.</p>
<p>When asking about the result below, we can realize that it'll return an <code>ActiveRecord::Relation</code> object.</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># rails console</span>

Student.where(<span class="hljs-symbol">name:</span> <span class="hljs-string">'Lynn'</span>).<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; Student::ActiveRecord_Relation</span>
</code></pre>
<p><code>ActiveRecord::Relation</code> class provides a <code>#to_sql</code> method, it will return sql statement for the relation after it is called.</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># rails console</span>

Student.where(<span class="hljs-symbol">name:</span> <span class="hljs-string">'Lynn'</span>).to_sql
<span class="hljs-comment">#=&gt; "SELECT \"students\".* FROM \"students\" WHERE \"students\".\"name\" = 'Lynn'"</span>
</code></pre>
<p>When we use <code>#to_sql</code> frequently, we can be more familiar with raw SQL.</p>
<h3 id="heading-3-practice-by-blazer-gem">3. Practice by Blazer gem</h3>
<p>Using <code>#to_sql</code> is like a learning process of input. Output is essential if we would like to be good at writing SQL.</p>
<p>[Blazer](Explore your data with SQL. Easily create charts and dashboards, and share them with your team.) is a Ruby gem.</p>
<blockquote>
<p>Explore your data with SQL. Easily create charts and dashboards, and share them with your team.</p>
</blockquote>
<p>After installing and configuring it to the application, we can write the raw SQL directly.</p>
<p>Blazer does help my SQL skills a lot.</p>
<p><img src="https://www.lynnbright.com/content/images/2022/08/image.png" alt /></p>
<p>Photo from: https://github.com/ankane/blazer</p>
<h3 id="heading-4-take-a-quiz-from-sqlzoo">4. Take a quiz from SQLZOO</h3>
<p><a target="_blank" href="https://sqlzoo.net/wiki/SQL_Tutorial">SQLZOO</a> is a SQL tutorial, which provides many query samples and quizzes that we can try. After learning by imitating and practicing writing SQL, I can finish more and more examination questions in SQLZOO now.</p>
<p>I have a sense of accomplishment during this learning process.</p>
<p>Hope you find this information helpful, also.</p>
]]></content:encoded></item><item><title><![CDATA[7 steps I usually do before I involve in a complex feature implementation]]></title><description><![CDATA[Before implementing a new feature, I like to make sure what problems we are going to solve, why we should solve them, and how much time we can implement this feature.
Here are 7 steps I usually do before I involve in a complex feature implementation....]]></description><link>https://lynnbright.com/7-steps-i-usually-do-before-i-involve-in-a-complex-feature-implementation</link><guid isPermaLink="true">https://lynnbright.com/7-steps-i-usually-do-before-i-involve-in-a-complex-feature-implementation</guid><category><![CDATA[Product Management]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Sun, 12 Jun 2022 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/bzqU01v-G54/upload/103b262583b6b605b6548acc72896417.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before implementing a new feature, I like to make sure what problems we are going to solve, why we should solve them, and how much time we can implement this feature.</p>
<p>Here are 7 steps I usually do before I involve in a complex feature implementation.</p>
<p>These steps bring many benefits to the development process. For example,</p>
<ul>
<li><p>Boost the accuracy of problem-solving.</p>
</li>
<li><p>Keep the mind clear and not get lost in the codebase.</p>
</li>
<li><p>Improve the efficiency of the implementation.</p>
</li>
<li><p>Communicate effectively and efficiently with other engineers.</p>
</li>
</ul>
<hr />
<p>Let's take the software onboarding for example. (<em>source:</em> <a target="_blank" href="https://www.appcues.com/blog/saas-user-onboarding"><em>What is SaaS onboarding?</em></a>)</p>
<h3 id="heading-1-define-the-problem">1. Define the problem</h3>
<p>When new users start to use the system, they might face different problems or say frustrations.</p>
<p>Here are some examples:</p>
<ul>
<li><p><em>New users don't know what they can do after registering an account.</em></p>
</li>
<li><p><em>New users are overwhelmed by the complicated usage of the system.</em></p>
</li>
<li><p><em>New users don't know how many steps they should do to complete all of the required settings.</em></p>
</li>
</ul>
<p>In some companies, <code>Define the problem</code> might not be the engineers' job. However, as an engineer, we still can collect the information from PMs or related team members.</p>
<p>They define the problem and we can try to understand what the problem is. This helps us get clear on what we are going to do and why solving this problem is important to the users and the company.</p>
<p>This step is the key point to help us build the right things.</p>
<h3 id="heading-2-write-down-the-user-story">2. Write down the user story</h3>
<p>When we fully understand the defined problem, it's time to brainstorm the solutions with your team members. If PMs have defined the user story, we still can discuss it with PMs, especially when we think the user story can be more specific or better.</p>
<p>Here are some user stories examples:</p>
<ul>
<li><p><em>As a user, I can watch a welcome video that can tell me what I can achieve with the system.</em></p>
</li>
<li><p><em>As a user, I can see a dashboard immediately after registering.</em></p>
</li>
<li><p><em>As a user, I can see the dashboard which lists all of the required tasks I need to complete before launching a website.</em></p>
</li>
<li><p><em>As a user, I can receive a newsletter that includes 3 recommended features that match my needs.</em></p>
</li>
</ul>
<h3 id="heading-3-write-the-poc">3. Write the POC</h3>
<p>After getting enough information, we finally can start to think about how to implement the feature.</p>
<p>Due to the feature being complex, I usually write down the POC (Proof of Concept) first.</p>
<p>POC is like a blueprint. When writing the POC, you will have many questions in your mind. In order to answer these questions, one of the approaches I will do is to explore the codebase.</p>
<h3 id="heading-4-explore-the-codebase">4. Explore the codebase</h3>
<p>Here are some questions usually in my mind:</p>
<ul>
<li><p>How many/Which models do I need? How about the association between models?</p>
</li>
<li><p>Does any data need to migrate before/after the feature releases?</p>
</li>
<li><p>Will the existed users be affected after the feature release? If the answer is yes, how many things need to be done first before I implement this feature?</p>
</li>
<li><p>If there are modules/services I can reuse?</p>
</li>
<li><p>How many modules/services that I need to re-design?</p>
</li>
<li><p>...more</p>
</li>
</ul>
<p>Exploring the codebase is a process to answer your questions, brainstorm better practices, and collect the limitation.</p>
<h3 id="heading-ia"> </h3>
<p>5. Design the code flow</p>
<p>After exploring the codebase, I like to make a simple code flow with Figma. This is a good way to keep the mind clear, not get lost in the codebase, and take care of different situations.</p>
<p><img src="https://www.lynnbright.com/content/images/2022/06/CleanShot-2022-06-12-at-16.31.08@2x.png" alt /></p>
<p>Fake code flow example</p>
<h3 id="heading-6-communicate-with-pms-and-other-engineers">6. Communicate with PMs and other engineers</h3>
<p>To make sure your design makes sense, the code flow source is useful, especially when you have a topic and want to discuss it with your tech leader or team members.</p>
<p>What's more, this can help the PR reviewers quickly understand which scope they are reviewing.</p>
<h3 id="heading-7-break-down-the-tasks">7. Break down the tasks</h3>
<p>The code flow is like a map, it helps us break down the tasks more easily.</p>
<p>If a task is smaller enough, it can be completed as soon as possible. Moreover, we can help reviewers to reduce the cognitive loading.</p>
<p>And the final step is: Just do it.</p>
<hr />
<p>I do not always follow these 7 steps sequentially, but these steps do improve my delivery efficiency and quality.</p>
<p>I hope you find this information helpful.</p>
]]></content:encoded></item><item><title><![CDATA[What's the difference between find_each, find_in_batches,  in_batches in Rails?]]></title><description><![CDATA[Sometimes we will use klass_name.all to get records from the database.
That’ll be ok, if we only have 100 records in the database.
However, using klass_name.all might not be the best way to get records, especially when we need to query large numbers ...]]></description><link>https://lynnbright.com/whats-the-difference-between-findeach-findinbatches-inbatches-in-rails</link><guid isPermaLink="true">https://lynnbright.com/whats-the-difference-between-findeach-findinbatches-inbatches-in-rails</guid><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Mon, 07 Feb 2022 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/wbXdGS_D17U/upload/9ebec3d516c3660bd8d9bcd42a6ae5c3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sometimes we will use <code>klass_name.all</code> to get records from the database.</p>
<p>That’ll be ok, if we only have 100 records in the database.</p>
<p>However, using <code>klass_name.all</code> might not be the best way to get records, especially when we need to query large numbers of records.</p>
<p>For example, when we have 1 million records and using the query below, ActiveRecord will instantiate all the objects at once. The memory consumption will increase quickly. The worst case is the application will be unable to load any additional program.</p>
<pre><code class="lang-ruby">Project.all.map { <span class="hljs-params">|p|</span> p.do_something_great }
</code></pre>
<p>Rails provides <code>find_each</code>, <code>find_in_batches</code>, and <code>in_batches</code> these three public methods to work with the records in batches, which helps reduce memory consumption.</p>
<p>What’s the difference between the three of them? Let’s see!</p>
<hr />
<h3 id="heading-findinbatches">find_in_batches</h3>
<p>Generally, if we do not specify the size of the batch, the default batch size is 1,000.</p>
<p>For example, there are 3,000 records, No.1~1,000 records will be the first batch, then No.1001~2000 will be the second batch, and so on.</p>
<p>If the block isn’t given to <code>find_in_batches</code>, it returns an Enumerator:</p>
<pre><code class="lang-ruby">Project.find_in_batches.<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; Enumerator &lt; Object</span>

Project.find_in_batches.first.<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; Array &lt; Object</span>
</code></pre>
<p>If the block is given...</p>
<p>After records of each batch finish <code>project.do_something_great!</code>, the type of <code>projects</code> will be changed to an array.</p>
<pre><code class="lang-ruby">Project.where(<span class="hljs-symbol">status:</span> <span class="hljs-string">'success'</span>).find_in_batches <span class="hljs-keyword">do</span> <span class="hljs-params">|projects|</span>
  projects.each { <span class="hljs-params">|project|</span> project.do_something_great! }
<span class="hljs-keyword">end</span>
</code></pre>
<hr />
<h3 id="heading-findeach">find_each</h3>
<p>The same as <code>find_in_batches</code>, the default batch size is 1,000.</p>
<p>If the block isn’t given to <code>find_each</code>, it returns an Enumerator:</p>
<pre><code class="lang-ruby">Project.find_each.<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; Enumerator &lt; Object</span>

Project.find_each.first.<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; Project &lt; ApplicationRecord</span>
</code></pre>
<p>If the block is given, it will call <code>find_in_batches</code>.</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># File activerecord/lib/active_record/relation/batches.rb, line 68</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">find_each</span><span class="hljs-params">(<span class="hljs-symbol">start:</span> <span class="hljs-literal">nil</span>, <span class="hljs-symbol">finish:</span> <span class="hljs-literal">nil</span>, <span class="hljs-symbol">batch_size:</span> <span class="hljs-number">1000</span>, <span class="hljs-symbol">error_on_ignore:</span> <span class="hljs-literal">nil</span>, <span class="hljs-symbol">order:</span> <span class="hljs-symbol">:asc</span>)</span></span>
  <span class="hljs-keyword">if</span> block_given?
    find_in_batches(<span class="hljs-symbol">start:</span> start, <span class="hljs-symbol">finish:</span> finish, <span class="hljs-symbol">batch_size:</span> batch_size, <span class="hljs-symbol">error_on_ignore:</span> error_on_ignore, <span class="hljs-symbol">order:</span> order) <span class="hljs-keyword">do</span> <span class="hljs-params">|records|</span>
      records.each { <span class="hljs-params">|record|</span> <span class="hljs-keyword">yield</span> record }
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">else</span>
    <span class="hljs-comment">#....</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>According to the source code, we can get the same result from the two queries below. So, if we would like to iterate in batches, we can use <code>find_each</code> as a shortcut.</p>
<pre><code class="lang-ruby">Project.where(<span class="hljs-symbol">status:</span> <span class="hljs-string">'success'</span>).find_in_batches <span class="hljs-keyword">do</span> <span class="hljs-params">|projects|</span>
  projects.each { <span class="hljs-params">|project|</span> project.do_something_great! }
<span class="hljs-keyword">end</span>

Project.where(<span class="hljs-symbol">status:</span> <span class="hljs-string">'success'</span>).find_each <span class="hljs-keyword">do</span> <span class="hljs-params">|project|</span>
  project.do_something_great!
<span class="hljs-keyword">end</span>
</code></pre>
<hr />
<h3 id="heading-inbatches">in_batches</h3>
<p>The default batch size is 1,000, too.</p>
<p>If the block isn’t given to <code>in_batches</code>, it returns a BatchEnumerator.</p>
<p>Different from <code>find_each</code> and <code>find_in_batches</code> return Enumerator, <code>in_batches</code> returns BatchEnumerator, and the type of each record is an ActiveRecord_Relation object.</p>
<pre><code class="lang-ruby">Project.in_batches.<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; ActiveRecord::Batches::BatchEnumerator &lt; Object</span>

Project.in_batches.first.<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; Project::ActiveRecord_Relation &lt; ActiveRecord::Relation</span>
</code></pre>
<p>If the block is given…</p>
<p>Yields ActiveRecord::Relation objects to work with a batch of records.</p>
<pre><code class="lang-ruby">Project.where(<span class="hljs-symbol">status:</span> <span class="hljs-string">'success'</span>)in_batches <span class="hljs-keyword">do</span> <span class="hljs-params">|projects|</span>
  projects.update_all(<span class="hljs-symbol">status:</span> <span class="hljs-string">'draft'</span>)
<span class="hljs-keyword">end</span>
</code></pre>
<hr />
<h4 id="heading-reference-info">Reference Info:</h4>
<ul>
<li><p><a target="_blank" href="https://api.rubyonrails.org/v6.1.3.1/classes/ActiveRecord/Batches.html">https://api.rubyonrails.org/v6.1.3.1/classes/ActiveRecord/Batches.html</a></p>
</li>
<li><p><a target="_blank" href="https://makandracards.com/makandra/1181-use-find_in_batches-or-find_each-to-deal-with-many-records-efficiently">https://makandracards.com/makandra/1181-use-find_in_batches-or-find_each-to-deal-with-many-records-efficiently</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[VS Code x Rubocop - ruby_executable_hooks: No such file or directory]]></title><description><![CDATA[Environment

macOS Monterey (Version 12.1)

Ruby 2.6.6

Ruby version manager: RVM

Editor: VS Code


To Reproduce:
I've installed rubocop gem in my app and add an extension ruby-rubocop in my VS Code.
Open VS Code and see the warning messages below. ...]]></description><link>https://lynnbright.com/vs-code-x-rubocop-rubyexecutablehooks-no-such-file-or-directory</link><guid isPermaLink="true">https://lynnbright.com/vs-code-x-rubocop-rubyexecutablehooks-no-such-file-or-directory</guid><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Thu, 27 Jan 2022 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/GnvurwJsKaY/upload/019f667e29918c3fc66a6ba31c122842.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-environment">Environment</h3>
<ul>
<li><p>macOS Monterey (Version 12.1)</p>
</li>
<li><p>Ruby 2.6.6</p>
</li>
<li><p>Ruby version manager: RVM</p>
</li>
<li><p>Editor: VS Code</p>
</li>
</ul>
<h3 id="heading-to-reproduce">To Reproduce:</h3>
<p>I've installed <code>rubocop</code> gem in my app and add an extension <code>ruby-rubocop</code> in my VS Code.</p>
<p>Open VS Code and see the warning messages below. This caused Rubocop cannot execute correctly.</p>
<pre><code class="lang-ruby">/Users/lynnbright/.rvm/gems/ruby-<span class="hljs-number">2.6</span>.<span class="hljs-number">6</span>/bin/rubocop returns empty output! please check configuration.

<span class="hljs-symbol">env:</span> <span class="hljs-symbol">ruby_executable_hooks:</span> No such file <span class="hljs-keyword">or</span> directory
</code></pre>
<h3 id="heading-how-to-solve-it">How to solve it:</h3>
<ol>
<li>Locate Rubocup:</li>
</ol>
<pre><code class="lang-ruby">$ which rubocup
<span class="hljs-comment"># /Users/lynnbright/.rvm/gems/ruby-2.6.6/bin/rubocop</span>
</code></pre>
<p>2. Replace <code>bin</code> with <code>wrappers</code>.</p>
<pre><code class="lang-plaintext">/Users/lynnbright/.rvm/gems/ruby-2.6.6/wrappers/rubocop
</code></pre>
<p>3. Go to your VS Code <code>Settings</code> page. You can press <code>command</code> + <code>,</code>.</p>
<p>4. Search <code>rubocup</code> or Find the tab <code>User &gt; Extensions &gt; Ruby-Rubocop &gt; Ruby › Rubocop: Execute Path</code>.</p>
<p>5. Paste Rubocop’s executable path:</p>
<pre><code class="lang-ruby">/Users/lynnbright/.rvm/gems/ruby-<span class="hljs-number">2.6</span>.<span class="hljs-number">6</span>/wrappers/
</code></pre>
<p><img src="https://www.lynnbright.com/content/images/2022/01/---2022-01-27---10.51.53.png" alt /></p>
<p>6. Restart your VS Code.</p>
<p>7. The warning messages might disappear and your Rubocup can execute correctly now!</p>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><a target="_blank" href="https://stackoverflow.com/questions/26247926/how-to-solve-usr-bin-env-ruby-executable-hooks-no-such-file-or-directory?ref=lynnbright.com">https://stackoverflow.com/questions/26247926/how-to-solve-usr-bin-env-ruby-executable-hooks-no-such-file-or-directory</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to define a multiline string in Ruby]]></title><description><![CDATA[Note: The following was tested with Ruby 2.6.6

Keyword: Heredoc

What is heredoc?
Heredoc is used for a form of multiline strings and preserves the line breaks and whitespace (including indentation) in the text.
How to define a heredoc in Ruby?
stri...]]></description><link>https://lynnbright.com/how-to-define-a-multiline-string-in-ruby</link><guid isPermaLink="true">https://lynnbright.com/how-to-define-a-multiline-string-in-ruby</guid><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Wed, 08 Dec 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/x3N59fMm0ME/upload/fbdbe096ecebc4ff9759d6491b35ce62.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Note: The following was tested with Ruby 2.6.6</em></p>
<blockquote>
<p>Keyword: Heredoc</p>
</blockquote>
<h3 id="heading-what-is-heredoc">What is heredoc?</h3>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Here_document">Heredoc</a> is used for a form of multiline strings and preserves the line breaks and whitespace (including indentation) in the text.</p>
<h3 id="heading-how-to-define-a-heredoc-in-ruby">How to define a heredoc in Ruby?</h3>
<pre><code class="lang-ruby">string = <span class="hljs-string">&lt;&lt;~HEREDOC
  How are you?
HEREDOC</span>
</code></pre>
<ul>
<li><p>Start with <code>&lt;&lt;-</code> or <code>&lt;&lt;~</code>.</p>
</li>
<li><p>The word <code>HEREDOC</code> can be replaced wit<a target="_blank" href="https://en.wikipedia.org/wiki/Here_document">h any t</a>ext, ex. <code>SQL</code>, <code>HTML</code><a target="_blank" href="https://en.wikipedia.org/wiki/Here_document">etc.</a></p>
</li>
<li><p>End with the word you have defined, ex. <code>HEREDOC</code>.</p>
</li>
</ul>
<h3 id="heading-how-to-use-string-interpolation-with-a-heredoc">How to use string interpolation with a heredoc?</h3>
<p>It's simple.</p>
<pre><code class="lang-ruby">string = <span class="hljs-string">&lt;&lt;~HEREDOC
  How are you, <span class="hljs-subst">#{User.first.name}</span>?
HEREDOC</span>
<span class="hljs-comment">#=&gt; "How are you, Lynn\n"</span>
</code></pre>
<p>If you would like to disable the interpolation, you can put th<a target="_blank" href="https://en.wikipedia.org/wiki/Here_document">e singl</a>e quotes around the heredoc name.</p>
<pre><code class="lang-ruby">string = <span class="hljs-string">&lt;&lt;~'HEREDOC'
  How are you, <span class="hljs-subst">#{User.first.name}</span>?
HEREDOC</span>
<span class="hljs-comment">#=&gt; "How are you, \#{User.first.name}?\n"</span>
</code></pre>
<h3 id="heading-whats-the-difference-between-ltlt-and-ltlt">What's the difference between <code>&lt;&lt;-</code> and <code>&lt;&lt;~</code>?</h3>
<p><code>&lt;&lt;-</code></p>
<pre><code class="lang-ruby">string = <span class="hljs-string">&lt;&lt;-HEREDOC
  Today is a nice day.
HEREDOC</span>
<span class="hljs-comment">#=&gt; "  Today is a nice day.\n"</span>
</code></pre>
<p><code>&lt;&lt;~</code></p>
<pre><code class="lang-ruby">string = <span class="hljs-string">&lt;&lt;~HEREDOC
  Today is a nice day.
HEREDOC</span>
<span class="hljs-comment">#=&gt; "Today is a nice day.\n"</span>
</code></pre>
<p><code>&lt;&lt;-</code> will maintain the original indentation. Ruby 2.3 introduce<a target="_blank" href="https://en.wikipedia.org/wiki/Here_document">d the s</a>quiggly heredoc <code>&lt;&lt;~</code> which can removes extra indentation.</p>
<h3 id="heading-how-to-remove-an-extra-newline">How to remove an extra newline?</h3>
<p>You might notice that there <a target="_blank" href="https://en.wikipedia.org/wiki/Here_document">is a new</a>line character <code>\n</code> at the e<a target="_blank" href="https://en.wikipedia.org/wiki/Here_document">nd of t</a>he return value. If you would like to remove an extra newline, <code>strip</code> will be useful.</p>
<pre><code class="lang-ruby">string = <span class="hljs-string">&lt;&lt;~HEREDOC.strip
  Today is a nice day.
HEREDOC</span>
<span class="hljs-comment">#=&gt; "Today is a nice day."</span>
</code></pre>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Here_document">https://en.wikipedia.org/wiki/Here_document</a></p>
</li>
<li><p><a target="_blank" href="https://www.rubyguides.com/2018/11/ruby-heredoc/">https://www.rubyguides.com/2018/11/ruby-heredoc</a></p>
</li>
<li><p><a target="_blank" href="https://blog.saeloun.com/2020/04/08/heredoc-in-ruby-and-rails">https://blog.saeloun.com/2020/04/08/heredoc-in-ruby-and-rails</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to turn on the expanded table formatting mode in PostgreSQL]]></title><description><![CDATA[Note: The following was tested with PostgreSQL 13.1
Default setting: \x off
$ psql myblog_dev

myblog_dev=# SELECT "users".* FROM "users" WHERE "users"."role" = 10 LIMIT 1;

The output format would be:

It was difficult to read the result.
Turn on th...]]></description><link>https://lynnbright.com/how-to-turn-on-the-expanded-table-formatting-mode-in-postgresql</link><guid isPermaLink="true">https://lynnbright.com/how-to-turn-on-the-expanded-table-formatting-mode-in-postgresql</guid><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Wed, 01 Dec 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/s9CC2SKySJM/upload/05cf025f25672871eae76fb6466bdc35.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong><em>Note: The following was tested with PostgreSQL 13.1</em></strong></p>
<h3 id="heading-default-setting-x-off">Default setting: <code>\x off</code></h3>
<pre><code class="lang-sql">$ psql myblog_dev

myblog_dev=<span class="hljs-comment"># SELECT "users".* FROM "users" WHERE "users"."role" = 10 LIMIT 1;</span>
</code></pre>
<p>The output format would be:</p>
<p><img src="https://www.lynnbright.com/content/images/2021/12/psql-myblog_dev-2021-12-01-17-44-49.png" alt /></p>
<p>It was difficult to read the result.</p>
<h3 id="heading-turn-on-the-expanded-table-formatting-mode-by-x-on">Turn on the expanded table formatting mode by <code>\x on</code>.</h3>
<pre><code class="lang-sql">$ psql myblog_dev

myblog_dev=<span class="hljs-comment"># \x on</span>
Expanded display is on.

myblog_dev=<span class="hljs-comment"># SELECT "users".* FROM "users" WHERE "users"."role" = 10 LIMIT 1;</span>
</code></pre>
<p>The output format would be:</p>
<p><img src="https://www.lynnbright.com/content/images/2021/12/psql-myblog_dev-2021-12-01-17-49-47.png" alt /></p>
<p>It became more pretty and readable!</p>
<hr />
<p>Switching the mode manually might be inconvenient. For example,</p>
<pre><code class="lang-sql">myblog_dev=<span class="hljs-comment"># \x on </span>

myblog_dev=<span class="hljs-comment"># select * from json_each_text('{ "name": "Lynn", "size": "S", "gender": "Female"}');</span>
</code></pre>
<p>I expected to got the format like this:</p>
<pre><code class="lang-sql">  key   | value
<span class="hljs-comment">--------+--------</span>
 name   | Lynn
 size   | S
 gender | Female
(3 rows)
</code></pre>
<p>However, the format I got looked like this:</p>
<pre><code class="lang-plaintext">-[ RECORD 1 ]-
key   | name
value | Lynn
-[ RECORD 2 ]-
key   | size
value | S
-[ RECORD 3 ]-
key   | gender
value | Female
</code></pre>
<p>It's simple to print the format I expect. All I need to do is switch <code>\x on</code> to <code>\x off</code>.</p>
<p>After PostgreSQL 9.2, we don't have to manually switch between the modes anymore. We can use <code>\x auto</code> and PostgreSQL fits records to the width of the screen automatically.</p>
<blockquote>
<p><strong>\x [ <em>on</em> | <em>off</em> | <em>auto</em> ]</strong> Sets or toggles expanded table formatting mode. As such it is equivalent to \pset expanded. (<a target="_blank" href="https://www.postgresql.org/docs/9.2/app-psql.html">Source</a>)</p>
</blockquote>
<pre><code class="lang-sql">myblog_dev=<span class="hljs-comment"># \x auto</span>
Expanded display is used automatically.

myblog_dev=<span class="hljs-comment"># select * from json_each_text('{ "name": "Lynn", "size": "S", "gender": "Female"}');</span>
  key   | value
<span class="hljs-comment">--------+--------</span>
 name   | Lynn
 size   | S
 gender | Female
(3 rows)


myblog_dev=<span class="hljs-comment"># SELECT "users".* FROM "users" WHERE "users"."role" = 10 LIMIT 1;</span>
-[ RECORD 1 ]<span class="hljs-comment">----------+-------------------------------------------------------------</span>
id                     | 1
email                  | my_email
encrypted_password     | $secret
reset_password_token   |
reset_password_sent_at |
remember_created_at    |
sign_in_count          | 0
current_sign_in_at     |
last_sign_in_at        |
current_sign_in_ip     |
last_sign_in_ip        |
confirmation_token     |
confirmed_at           |
confirmation_sent_at   |
unconfirmed_email      |
failed_attempts        | 0
unlock_token           |
locked_at              |
created_at             | 2021-05-24 10:55:33.368015
updated_at             | 2021-05-24 12:02:59.605434
role                   | 10
name                   |
subscribe_edm          | {}
</code></pre>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://www.postgresql.org/docs/9.2/app-psql.html">https://www.postgresql.org/docs/9.2/app-psql.html</a></p>
</li>
<li><p><a target="_blank" href="https://www.postgresql.org/docs/9.5/functions-json.html">https://www.postgresql.org/docs/9.5/functions-json.html</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/9604723/alternate-output-format-for-psql-showing-one-column-per-line-with-column-name/16108898#16108898">https://stackoverflow.com/questions/9604723/alternate-output-format-for-psql-showing-one-column-per-line-with-column-name/16108898#16108898</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[6 tips to ensure your rake task runs smoothly]]></title><description><![CDATA[Rake is a task runner/task management tool in Ruby.
You can create diverse tasks, put tasks in the Rakefile, and execute a command like rake :your_awesome_task. Your task will start running by Rake.
In Ruby, you can put task code inside a file named ...]]></description><link>https://lynnbright.com/6-tips-to-ensure-your-rake-task-runs-smoothly</link><guid isPermaLink="true">https://lynnbright.com/6-tips-to-ensure-your-rake-task-runs-smoothly</guid><category><![CDATA[Ruby on Rails]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Sun, 14 Nov 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/fMD_Cru6OTk/upload/2b4556c093c9b64a746a0fdcac75f69c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Rake is a task runner/task management tool in Ruby.</p>
<p>You can create diverse tasks, put tasks in the <code>Rakefile</code>, and execute a command like <code>rake :your_awesome_task</code>. Your task will start running by Rake.</p>
<p>In Ruby, you can put task code inside a file named <code>Rakefile</code>, <code>rakefile</code>, <code>Rakefile.rb</code> or <code>rakefile.rb</code>.</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># rakefile.rb</span>

desc <span class="hljs-string">'Say hello'</span>
task <span class="hljs-symbol">:say_hello</span> <span class="hljs-keyword">do</span>
  puts <span class="hljs-string">'Hello!'</span>
<span class="hljs-keyword">end</span>

<span class="hljs-comment"># In your terminal</span>
$ rake say_hello
<span class="hljs-comment">#=&gt; Hello!</span>
</code></pre>
<p>In Rails, you can put task code under the <code>lib/tasks</code> folder.</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># lib/tasks/say_hello.rake</span>

desc <span class="hljs-string">'Say hello'</span>
task <span class="hljs-symbol">say_hello:</span> <span class="hljs-symbol">:environment</span> <span class="hljs-keyword">do</span>
  user = User.first
  puts <span class="hljs-string">"Hello, <span class="hljs-subst">#{user.name}</span>!"</span>
<span class="hljs-keyword">end</span>

<span class="hljs-comment"># In your terminal</span>
$ rake say_hello
<span class="hljs-comment">#=&gt; Hello, Lynn!</span>
</code></pre>
<p>Rake is used for common administration tasks. Some commands you might be probably familiar with, such as <code>rake db:migrate</code>, <code>rake generate model</code>, <code>rake routes</code>. (Take a look at <a target="_blank" href="https://guides.rubyonrails.org/v4.2/command_line.html#rake">more rake commands</a>.)</p>
<p>Rake is useful when we need to update column values in the database. There are 6 tips I often use to ensure records can be updated smoothly when running a rake task.</p>
<hr />
<h3 id="heading-tips1-ask-yourself-4-questions">Tips1: Ask yourself 4 questions</h3>
<ol>
<li><p>The assumption of the column value is as your expectation?</p>
</li>
<li><p>What will happen if the assumption isn't true?</p>
</li>
<li><p>How do you know when something went wrong?</p>
</li>
<li><p>How can you fix errors immediately when something went wrong?</p>
</li>
</ol>
<p>These 4 questions can help us manage risks that might happen when running a task.</p>
<h3 id="heading-tips2-collect-failed-records-list">Tips2: Collect failed records list</h3>
<ul>
<li><p>Use <code>!</code> (ex. <code>save!</code> , <code>update!</code> etc) to raise an exception if a validation error occurs.</p>
</li>
<li><p>Rescue the error, then you can collect the failed records and failed reason.</p>
</li>
</ul>
<p>You can understand why, how many, and which records don't update successfully by collecting a failed records list. It's usable to fix failed cases.</p>
<pre><code class="lang-ruby">namespace <span class="hljs-symbol">:user</span> <span class="hljs-keyword">do</span>
  desc <span class="hljs-string">'update name'</span>
  task <span class="hljs-symbol">update_name:</span> <span class="hljs-symbol">:environment</span> <span class="hljs-keyword">do</span>
    failed_list = []

    User.find_each <span class="hljs-keyword">do</span> <span class="hljs-params">|user|</span>
      user.update!(<span class="hljs-symbol">name:</span> <span class="hljs-string">"best-<span class="hljs-subst">#{user.name}</span>"</span>)

    <span class="hljs-keyword">rescue</span> StandardError =&gt; e
      failed_list.push({ <span class="hljs-symbol">user_id:</span> user.id, <span class="hljs-symbol">reason:</span> user.inspect })

      Rails.logger.error <span class="hljs-string">"[task] user_id: <span class="hljs-subst">#{user.id}</span> failed to update user name."</span>
      Rails.logger.error <span class="hljs-string">"[task] user_id: <span class="hljs-subst">#{user.id}</span> failed reason: <span class="hljs-subst">#{e.inspect}</span>"</span>
    <span class="hljs-keyword">end</span>

    Rails.logger.info <span class="hljs-string">"[task] Failed list: <span class="hljs-subst">#{failed_list}</span>"</span>
    p <span class="hljs-string">"[task] Failed list: <span class="hljs-subst">#{failed_list}</span>"</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h3 id="heading-tips3-record-a-task-running-duration">Tips3: Record a task running duration</h3>
<ul>
<li>Record <code>start_at</code> and <code>end_at</code> timestamp.</li>
</ul>
<p>Sometimes the system needs downtime when we run a task. However, downtime is expensive because it will impact the revenue of the company.</p>
<p>Before running a task on the production environment, running a task on the staging and recording a running duration can help us estimate how much time the task will spend. This will be a piece of important information to communicate with PMs or other departments.</p>
<pre><code class="lang-ruby">namespace <span class="hljs-symbol">:user</span> <span class="hljs-keyword">do</span>
  desc <span class="hljs-string">'update name'</span>
  task <span class="hljs-symbol">update_name:</span> <span class="hljs-symbol">:environment</span> <span class="hljs-keyword">do</span>

    start_at = Time.zone.now
    Rails.logger.info <span class="hljs-string">"[task] Start to update users name. Time: <span class="hljs-subst">#{start_at}</span>"</span>

    User.find_each <span class="hljs-keyword">do</span> <span class="hljs-params">|user|</span>
      <span class="hljs-comment">#...</span>
    <span class="hljs-keyword">end</span>

    end_at = Time.zone.now
    duration = ((end_at - start_at) / <span class="hljs-number">60</span>.seconds).to_i
    Rails.logger.info <span class="hljs-string">"[task] All of user records update completed. Time: <span class="hljs-subst">#{end_at}</span>"</span>
    p <span class="hljs-string">"[task] Start to update users name. Time: <span class="hljs-subst">#{start_at}</span>"</span>
    p <span class="hljs-string">"[task] All of user records update completed. Time: <span class="hljs-subst">#{end_at}</span>"</span>
    p <span class="hljs-string">"[task] Task running duration: <span class="hljs-subst">#{duration}</span> minutes"</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h3 id="heading-tips4-make-current-progress-visible">Tips4: Make current progress visible</h3>
<p>Print how many records you have updated now.</p>
<p>If you don't print anything when you run a task, your terminal will be very silent. Printing the log can help you keep track of the current progress. I believe this is an essential user experience for developers. 😂</p>
<pre><code class="lang-ruby">namespace <span class="hljs-symbol">:user</span> <span class="hljs-keyword">do</span>
  desc <span class="hljs-string">'update name'</span>
  task <span class="hljs-symbol">update_name:</span> <span class="hljs-symbol">:environment</span> <span class="hljs-keyword">do</span>

    user_updated_count = <span class="hljs-number">0</span>

    User.find_each <span class="hljs-keyword">do</span> <span class="hljs-params">|user|</span>
      user.update!(<span class="hljs-symbol">name:</span> <span class="hljs-string">"best-<span class="hljs-subst">#{user.name}</span>"</span>)

      user_updated_count += <span class="hljs-number">1</span>
      p <span class="hljs-string">"Current updated count =&gt; <span class="hljs-subst">#{user_updated_count}</span>"</span>
    <span class="hljs-keyword">end</span>

    Rails.logger.info <span class="hljs-string">"[task] Final: Update <span class="hljs-subst">#{user_updated_count}</span> user records."</span>
    p <span class="hljs-string">"[task] Final: Update <span class="hljs-subst">#{user_updated_count}</span> user records."</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h3 id="heading-tips5-add-a-confirmation-step-to-your-task">Tips5: Add a confirmation step to your task</h3>
<p>Some tasks are destructive, so avoiding the fat-finger problem is crucial.</p>
<pre><code class="lang-ruby">namespace <span class="hljs-symbol">:user</span> <span class="hljs-keyword">do</span>
  desc <span class="hljs-string">'replace_data'</span>
  task <span class="hljs-symbol">replace_data:</span> [<span class="hljs-symbol">:environment</span>, <span class="hljs-symbol">:confirm_to_replace_data</span>] <span class="hljs-keyword">do</span>
    <span class="hljs-comment">#...</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

desc <span class="hljs-string">'confirm to replace data'</span>
task <span class="hljs-symbol">:confirm_to_replace_data</span> <span class="hljs-keyword">do</span>
  confirm_token = rand(<span class="hljs-number">36</span>**<span class="hljs-number">6</span>).to_s(<span class="hljs-number">36</span>)
  $stdout.puts <span class="hljs-string">"[WARNING!!] Please enter confirmation code if you confirm to replace user data: <span class="hljs-subst">#{confirm_token}</span>"</span>
  input = $stdin.gets.chomp

  raise <span class="hljs-string">"Aborted! Confirmation code <span class="hljs-subst">#{input}</span> is invalid."</span> <span class="hljs-keyword">unless</span> input == confirm_token.to_s

  Rails.logger.info <span class="hljs-string">"Confirm to replace. Time: <span class="hljs-subst">#{Time.zone.now}</span>"</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h3 id="heading-tips6-write-some-test-cases-for-your-task">Tips6: Write some test cases for your task</h3>
<p>Last but not least, remember to write tests for your task. This can ensure your assumption is as you think.</p>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://guides.rubyonrails.org/v4.2/command_line.html">https://guides.rubyonrails.org/v4.2/command_line.html</a></p>
</li>
<li><p><a target="_blank" href="https://www.rubyguides.com/2019/02/ruby-rake">https://www.rubyguides.com/2019/02/ruby-rake</a></p>
</li>
<li><p><a target="_blank" href="https://coderwall.com/p/_ftisa/add-a-confirmation-step-to-your-rake-tasks">https://coderwall.com/p/_ftisa/add-a-confirmation-step-to-your-rake-tasks</a></p>
</li>
<li><p><a target="_blank" href="https://5xcampus.com/posts/write-rake-to-export-report-easily">https://5xcampus.com/posts/write-rake-to-export-report-easily</a></p>
</li>
<li><p><a target="_blank" href="https://dwye.dev/post/rake">https://dwye.dev/post/rake</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to Benchmark my code in Ruby or Rails]]></title><description><![CDATA[Recently, I had a job to fix the slow code. Before diving into fixing the slow code, I used Scout APM to identify the performance bottlenecks, which helped me make sure where the slow code is.
To prove the new optimization solution is faster, in addi...]]></description><link>https://lynnbright.com/how-to-benchmark-my-code-in-ruby-or-rails</link><guid isPermaLink="true">https://lynnbright.com/how-to-benchmark-my-code-in-ruby-or-rails</guid><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Sat, 18 Sep 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/atSaEOeE8Nk/upload/3b87894f86e7dbc5759348e18d83ba40.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I had a job to fix the slow code. Before diving into fixing the slow code, I used Scout APM to identify the performance bottlenecks, which helped me make sure where the slow code is.</p>
<p>To prove the new optimization solution is faster, in addition to checking the before-after response time in the log file, I think I need a more efficient tool to evaluate the solution.</p>
<h3 id="heading-benchmarking">Benchmarking</h3>
<p>Benchmarking is a way of measuring the performance of the code. It can answer the question like 'Which one is faster, A or B?'</p>
<p>Ruby has a benchmarking tool called <code>Benchmark</code> in its standard library. Benchmark module provides methods to measure and report the time used to execute Ruby code.</p>
<h4 id="heading-how-to-use-ruby-benchmark-module">How to use Ruby Benchmark module?</h4>
<p>You can add a Ruby file first.</p>
<pre><code class="lang-plaintext">$ touch test.rb
</code></pre>
<p>You should <code>require 'benchmark'</code> to make sure you can use it. Next, put the code that you would like to test into the <code>x.report { #put your code here }</code> block.</p>
<pre><code class="lang-ruby"><span class="hljs-keyword">require</span> <span class="hljs-string">'benchmark'</span>

n = <span class="hljs-number">100</span>
Benchmark.bm <span class="hljs-keyword">do</span> <span class="hljs-params">|x|</span>
  x.report(<span class="hljs-string">'A'</span>) { <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-number">1</span>..n; a = <span class="hljs-string">'1'</span>; <span class="hljs-keyword">end</span> }
  x.report(<span class="hljs-string">'B'</span>) { n.times <span class="hljs-keyword">do</span>   ; a = <span class="hljs-string">'1'</span>; <span class="hljs-keyword">end</span> }
  x.report(<span class="hljs-string">'C'</span>) { <span class="hljs-number">1</span>.upto(n) <span class="hljs-keyword">do</span> ; a = <span class="hljs-string">'1'</span>; <span class="hljs-keyword">end</span> }
<span class="hljs-keyword">end</span>
</code></pre>
<p>Go back to the terminal and execute the file:</p>
<p>We can see the C plan is faster than the A or B plan.</p>
<pre><code class="lang-plaintext">$ ruby test.rb
       user     system      total        real
A  0.000026   0.000005   0.000031 (  0.000024)
B  0.000018   0.000001   0.000019 (  0.000018)
C  0.000016   0.000001   0.000017 (  0.000017)
</code></pre>
<blockquote>
<p>This report shows the user CPU time, system CPU time, the sum of the user and system CPU times, and the elapsed real time. The unit of time is seconds. (<a target="_blank" href="https://ruby-doc.org/stdlib-2.7.3/libdoc/benchmark/rdoc/Benchmark.html">Source</a>)</p>
</blockquote>
<h4 id="heading-another-enhancement-benchmarking-gem-benchmark-ipshttpsgithubcomevanphxbenchmark-ips">Another enhancement benchmarking gem - <a target="_blank" href="https://github.com/evanphx/benchmark-ips">benchmark-ips</a></h4>
<p>When searching the benchmarking tool, I found out another interesting gem called benchmark-ips.</p>
<h4 id="heading-feature">Feature</h4>
<blockquote>
<p>An iterations per second enhancement to Benchmark.</p>
</blockquote>
<h4 id="heading-whats-the-difference-between-the-traditional-benchmark-library-and-benchmark-ips">What's the difference between the traditional Benchmark library and benchmark-ips?</h4>
<blockquote>
<p>Benchmark/ips will report the number of iterations per second for a given block of code. <strong>When analyzing the results, notice the percent of</strong> <a target="_blank" href="http://en.wikipedia.org/wiki/Standard_deviation"><strong>standard deviation</strong></a> <strong>which tells us how spread out our measurements are from the average.</strong> A high standard deviation could indicate the results having too much variability.</p>
</blockquote>
<p>benchmark-ips uses <a target="_blank" href="http://en.wikipedia.org/wiki/Standard_deviation">standard deviation</a> which is the concept of Statistics to analyze the result. The benefit is that we can literally make sure the result is significant/extreme significant/no significant difference.</p>
<p>In other words, take the result above for example:</p>
<p>C plan seems to be faster than the A or B plan, but it might not be the fact.</p>
<pre><code class="lang-plaintext"># n = 100
$ ruby test.rb
       user     system      total        real
A  0.000026   0.000005   0.000031 (  0.000024)
B  0.000018   0.000001   0.000019 (  0.000018)
C  0.000016   0.000001   0.000017 (  0.000017)
</code></pre>
<p>Let's use benchmark-ips to analyze the result:</p>
<pre><code class="lang-ruby"><span class="hljs-keyword">require</span> <span class="hljs-string">"benchmark/ips"</span>

n = <span class="hljs-number">100</span>
Benchmark.ips <span class="hljs-keyword">do</span> <span class="hljs-params">|x|</span>
  x.report(<span class="hljs-string">'A'</span>) { <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-number">1</span>..n; a = <span class="hljs-string">"1"</span>; <span class="hljs-keyword">end</span> }
  x.report(<span class="hljs-string">'B'</span>) { n.times <span class="hljs-keyword">do</span>  ; a = <span class="hljs-string">"1"</span>; <span class="hljs-keyword">end</span> }
  x.report(<span class="hljs-string">'C'</span>) { <span class="hljs-number">1</span>.upto(n) <span class="hljs-keyword">do</span> ; a = <span class="hljs-string">"1"</span>; <span class="hljs-keyword">end</span> }

  x.compare!
<span class="hljs-keyword">end</span>
</code></pre>
<p>There is something interesting:</p>
<ul>
<li>B plan seems to iterate more times per second than the A or C plan.</li>
</ul>
<pre><code class="lang-plaintext">Warming up --------------------------------------
                   A    11.038k i/100ms
                   B    11.868k i/100ms
                   C    12.166k i/100ms
Calculating -------------------------------------
                   A    125.949k (± 3.9%) i/s -    629.166k in   5.003441s
                   B    126.662k (± 2.7%) i/s -    640.872k in   5.063567s
                   C    125.172k (± 6.3%) i/s -    632.632k in   5.076965s

Comparison:
                   B:   126662.1 i/s
                   A:   125949.4 i/s - same-ish: difference falls within error
                   C:   125172.4 i/s - same-ish: difference falls within error
</code></pre>
<p>From the perspective of Statistics, there is not a meaningful difference between the three plans. When I change <code>n=100</code> to <code>n=10000</code>, the result is the same. I feel very surprised about the result. Very. (Please correct me if I misunderstood. 🙏)</p>
<h3 id="heading-how-to-benchmark-the-code-in-rails">How to Benchmark the code in Rails</h3>
<p>It's simple. Just add <code>require_relative '../../config/environment'</code> so that you can use the model class you have built in your Rails App.</p>
<pre><code class="lang-ruby"><span class="hljs-keyword">require</span> <span class="hljs-string">'benchmark/ips'</span>
require_relative <span class="hljs-string">'../../config/environment'</span>

transaction_ids = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-comment">#....]</span>
transactions = Transaction.where(<span class="hljs-symbol">id:</span> transaction_ids)

Benchmark.ips <span class="hljs-keyword">do</span> <span class="hljs-params">|x|</span>
  x.report(<span class="hljs-string">'new'</span>) <span class="hljs-keyword">do</span>
    transactions.map(&amp;<span class="hljs-symbol">:some_column</span>).compact
  <span class="hljs-keyword">end</span>

  x.report(<span class="hljs-string">'old'</span>) <span class="hljs-keyword">do</span>
    transaction_records = transactions.
      includes(<span class="hljs-symbol">:a_table</span>, <span class="hljs-symbol">:b_table</span>, <span class="hljs-symbol">:c_table</span>).order(<span class="hljs-symbol">created_at:</span> <span class="hljs-symbol">:desc</span>)

    transaction_records.map(&amp;<span class="hljs-symbol">:some_column</span>).compact
  <span class="hljs-keyword">end</span>

  x.compare!
<span class="hljs-keyword">end</span>
</code></pre>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://shopify.engineering/how-fix-slow-code-ruby">https://shopify.engineering/how-fix-slow-code-ruby</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/evanphx/benchmark-ips">https://github.com/evanphx/benchmark-ips</a></p>
</li>
<li><p><a target="_blank" href="https://blog.saeloun.com/2020/02/11/rails-benchmark-generator">https://blog.saeloun.com/2020/02/11/rails-benchmark-generator</a></p>
</li>
<li><p><a target="_blank" href="https://guides.rubyonrails.org/v3.2.13/performance_testing.html#helper-methods">https://guides.rubyonrails.org/v3.2.13/performance_testing.html#helper-methods</a></p>
</li>
<li><p><a target="_blank" href="https://ihower.tw/rails/performance.html">https://ihower.tw/rails/performance.html</a></p>
</li>
<li><p><a target="_blank" href="https://www.schneems.com/2016/11/14/statistical-lit.html">https://www.schneems.com/2016/11/14/statistical-lit.html</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Lessons learned from failing to access an environment variable in YMAL file]]></title><description><![CDATA[Note: The following was tested with Ruby 2.6.6 / Rails 5.2.6.
Situation
I tried to add an environment variable in the application.yml file.
# config/application.yml

default:
  #...
  API_TOKEN: ABC123456

And I expected when executing ENV['API_TOKEN...]]></description><link>https://lynnbright.com/lessons-learned-from-failing-to-access-an-environment-variable-in-ymal-file</link><guid isPermaLink="true">https://lynnbright.com/lessons-learned-from-failing-to-access-an-environment-variable-in-ymal-file</guid><category><![CDATA[Ruby on Rails]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Thu, 09 Sep 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/hBuwVLcYTnA/upload/b82cafe394c0e13aa72c13a1b6f3664d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong><em>Note: The following was tested with Ruby 2.6.6 / Rails 5.2.6.</em></strong></p>
<h2 id="heading-situation">Situation</h2>
<p>I tried to add an environment variable in the <code>application.yml</code> file.</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># config/application.yml</span>

<span class="hljs-attr">default:</span>
  <span class="hljs-comment">#...</span>
  <span class="hljs-attr">API_TOKEN:</span> <span class="hljs-string">ABC123456</span>
</code></pre>
<p>And I expected when executing <code>ENV['API_TOKEN']</code> in Rails console, I would get <code>ABC123456</code>. But I got nil.</p>
<pre><code class="lang-ruby">$ rails console
$ ENV[<span class="hljs-string">'API_TOKEN'</span>]
<span class="hljs-comment">#=&gt; nil</span>
</code></pre>
<p>To see if I can figure out what's going on, I tried to do something below.</p>
<hr />
<h2 id="heading-problem-solving-process">Problem-solving process</h2>
<ul>
<li><p>If we edit any files which were used to start the application, like configs or initializers, the application needs to be restarted. So, I thought that <code>reload!</code> in Rails console might reload the new code and solve this problem. However, I got the nil result the same.</p>
</li>
<li><p>Next, I google the keyword: 'rails console nil ymal env'. Not a good keyword, but I got another important keyword: <code>spring stop</code>.</p>
</li>
</ul>
<h3 id="heading-whats-spring">What's Spring?</h3>
<blockquote>
<p>Spring is a Rails application <strong>preloader</strong>. It speeds up development by keeping your application running in the background so you don't need to boot it every time you run a test, rake task or migration. (<a target="_blank" href="https://github.com/rails/spring/blob/master/README.md">Source</a>)</p>
</blockquote>
<h4 id="heading-springs-feature">Spring's Feature</h4>
<ul>
<li><p>Totally automatic; no need to explicitly start and stop the background process</p>
</li>
<li><p>Reloads your application code on each run</p>
</li>
<li><p>Restarts your application when configs / initializers / gem dependencies are changed</p>
</li>
</ul>
<h3 id="heading-what-was-the-result-i-got-in-rails-console-after-executing-spring-stop">What was the result I got in Rails console after executing <code>spring stop</code> ?</h3>
<p>I succeeded in accessing the environment variable!</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># In the terminal</span>
$ spring stop
<span class="hljs-comment">#=&gt; Spring stopped.</span>

$ rails console
$ ENV[<span class="hljs-string">'API_TOKEN'</span>]
<span class="hljs-comment">#=&gt; ABC123456</span>
</code></pre>
<h3 id="heading-so-why-spring-stop-can-solve-this-problem">So, why <code>spring stop</code> can solve this problem?</h3>
<p>According to the Spring's README:</p>
<blockquote>
<p>But if we edit any of the files which were used to start the application (configs, initializers, your gemfile), the application needs to be fully restarted. <strong>This happens automatically</strong>.</p>
</blockquote>
<p>After I change the config file, Spring should re-run. That means Spring will reload the application code.</p>
<p>But the result seemed not as I expected. Even though I have changed the YAML file and restarted Rails console, but Spring didn't re-run automatically. I guessed that Spring saw that my YMAL file didn't change.</p>
<p>So, I stopped Spring running first and then re-ran it by restarting Rails console.</p>
<p>We can check out the following block:</p>
<pre><code class="lang-ruby">$ spring stop
<span class="hljs-comment">#=&gt; Spring stopped.</span>

$ bin/spring status
<span class="hljs-comment">#=&gt; Spring is not running.</span>

$ rails console
<span class="hljs-comment">#=&gt; ...Running via Spring preloader in process 1182</span>
<span class="hljs-comment">#=&gt; Loading development environment (Rails 5.2.6)</span>
$ ENV[<span class="hljs-string">'API_TOKEN'</span>]
<span class="hljs-comment">#=&gt; ABC123456</span>
$ exit

$ bin/spring status
<span class="hljs-comment">#=&gt; Spring is running:</span>

<span class="hljs-comment"># 1171 spring server | backme | started 14 secs ago</span>
<span class="hljs-comment"># 1172 ruby -I /Users/yuchu/.rvm/rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0 -I # /Users/yuchu/.rvm/gems/ruby-2.6.6/gems/spring-2.1.1/lib -e require 'spring/application/boot'</span>
</code></pre>
<p>Rails console ran via Spring preloader and Spring started 14 secs ago. Spring has reloaded the application's newest code now.</p>
<p>I thought that was the exact reason why the environment variable <code>ENV['API_TOKEN']</code> could be accessed successfully.</p>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/8686215/failing-to-access-environment-variables-within-database-yml-file?ref=lynnbright.com">https://stackoverflow.com/questions/8686215/failing-to-access-environment-variables-within-database-yml-file</a></p>
</li>
<li><p><a target="_blank" href="https://ithelp.ithome.com.tw/articles/10223709?ref=lynnbright.com">https://ithelp.ithome.com.tw/articles/10223709</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/rails/spring/blob/main/README.md">https://github.com/rails/spring/blob/main/README.md</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[When ORDER BY and NULL work together]]></title><description><![CDATA[When we would like to sort the result-set in ascending or descending, we can use ORDER BY in SQL query. In Rails, we can use order which is derived from ActiveRecord::QueryMethods. For example,
Article.all.order(published_at: :desc)

Let's focus on t...]]></description><link>https://lynnbright.com/when-order-by-and-null-work-together</link><guid isPermaLink="true">https://lynnbright.com/when-order-by-and-null-work-together</guid><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Fri, 03 Sep 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/FlPc9_VocJ4/upload/6f1f2348917e8a53e5f63a18e4ec439b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When we would like to sort the result-set in ascending or descending, we can use ORDER BY in SQL query. In Rails, we can use <code>order</code> which is derived from <code>ActiveRecord::QueryMethods</code>. For example,</p>
<pre><code class="lang-ruby">Article.all.order(<span class="hljs-symbol">published_at:</span> <span class="hljs-symbol">:desc</span>)
</code></pre>
<p>Let's focus on the <code>published_at</code> attribute now.</p>
<blockquote>
<p>What will happen if one of the article records' <code>published_at</code> value is nil and we are going to sort the result-set in descending?</p>
</blockquote>
<pre><code class="lang-ruby">$ article1 = Article.create(<span class="hljs-symbol">title:</span> <span class="hljs-string">'A1'</span>, <span class="hljs-symbol">published_at:</span> <span class="hljs-literal">nil</span>)
$ article2 = Article.create(<span class="hljs-symbol">title:</span> <span class="hljs-string">'A2'</span>, <span class="hljs-symbol">published_at:</span> Time.zone.now)
$ article3 = Article.create(<span class="hljs-symbol">title:</span> <span class="hljs-string">'A3'</span>, <span class="hljs-symbol">published_at:</span> Time.zone.now - <span class="hljs-number">2</span>.days)
</code></pre>
<p>According to the query below, we could find out the result in order was article1, article2, article3. article1 whose <code>published_at</code> is nil was placed at the head of the result.</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># Database: PostgreSQL</span>
$ Article.where(<span class="hljs-symbol">id:</span> [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>]).order(<span class="hljs-symbol">published_at:</span> <span class="hljs-symbol">:desc</span>)
  Article Load (<span class="hljs-number">1.9</span>ms)  SELECT <span class="hljs-string">"articles"</span>.* FROM <span class="hljs-string">"articles"</span> WHERE <span class="hljs-string">"articles"</span>.<span class="hljs-string">"id"</span> IN ($1, $2, $3) ORDER BY <span class="hljs-string">"articles"</span>.<span class="hljs-string">"published_at"</span> DESC LIMIT $4  [[<span class="hljs-string">"id"</span>, <span class="hljs-number">1</span>], [<span class="hljs-string">"id"</span>, <span class="hljs-number">2</span>], [<span class="hljs-string">"id"</span>, <span class="hljs-number">3</span>], [<span class="hljs-string">"LIMIT"</span>, <span class="hljs-number">11</span>]]

 =&gt; #&lt;ActiveRecord::Relation [
 #&lt;Article id: 1, title: "A1", content: "", status: "publish", created_at: "2021-02-16 13:40:58", updated_at: "2021-02-28 03:35:34", published_at: nil&gt;, 
 #&lt;Article id: 2, title: "A2", content: "", status: "publish", created_at: "2021-02-16 14:08:34", updated_at: "2021-09-01 16:19:30", published_at: "2021-09-01 16:19:27"&gt;, 
 #&lt;Article id: 3, title: "A3", content: "", status: "publish", created_at: "2021-02-16 14:13:15", updated_at: "2021-09-01 16:19:48", published_at: "2021-08-30 16:19:45"&gt;
 ]&gt;
</code></pre>
<p>I'm curious why NULL values come first when using ORDER BY.</p>
<blockquote>
<p>If you apply the ORDER BY clause to a column with NULLs, the NULL values will be placed either first or last in the result set. <strong>The output depends on the database type.</strong> (<a target="_blank" href="https://learnsql.com/blog/how-to-order-rows-with-nulls/">Source</a>)</p>
</blockquote>
<p>In my project I use PostgreSQL, <strong>by default, PostgreSQL considers NULL values larger than any non-NULL value</strong>.</p>
<p>That's why the record whose <code>published_at == nil</code> came first when using ORDER BY in descending order.</p>
<hr />
<h3 id="heading-how-can-i-do-if-i-would-like-to-order-by-column1-if-column1-is-not-null-otherwise-order-by-column2">How can I do if I would like to "Order by Column1 if Column1 is not null, otherwise order by Column2"?</h3>
<p>For instance, when <code>published_at == nil</code> , I hope to replace <code>published_at</code> with <code>created_at</code> to be ordered.</p>
<p>PostgreSQL provides a wonderful function - <code>COALESCE</code>. It will return the first non-NULL argument. Let's jump into PostgreSQL to take a look at how it executes:</p>
<pre><code class="lang-SQL">$ psql postgres
$ postgres=<span class="hljs-comment"># \c myblog_dev</span>
$ myblog_dev=<span class="hljs-comment"># SELECT COALESCE (1, 2);</span>
 coalesce
<span class="hljs-comment">----------</span>
        1
(1 row)
<span class="hljs-comment">#=&gt; `1` is the first non-NULL argument </span>

$ myblog_dev=<span class="hljs-comment"># SELECT COALESCE (null, 2, 1);</span>
 coalesce
<span class="hljs-comment">----------</span>
        2
(1 row)
<span class="hljs-comment">#=&gt; `2` is the first non-NULL argument</span>

$ myblog_dev=<span class="hljs-comment"># SELECT COALESCE (null, null, null);</span>
 coalesce
<span class="hljs-comment">----------</span>

(1 row)
<span class="hljs-comment">#=&gt; There is no any non-NULL argument.</span>
</code></pre>
<p>The SQL statement:</p>
<pre><code class="lang-ruby">SELECT * FROM articles ORDER BY COALESCE(published_at, created_at) DESC;
</code></pre>
<p><code>COALESCE</code> can be used in ActiveRecord Query Interface, too:</p>
<pre><code class="lang-ruby">Article.where(<span class="hljs-symbol">id:</span> [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>]).order(<span class="hljs-string">'COALESCE(published_at, created_At) DESC'</span>)
<span class="hljs-comment">#=&gt; Article Load (1.0ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" IN ($1, $2, $3) ORDER BY COALESCE(published_at, created_At) DESC LIMIT $4  [["id", 1], ["id", 2], ["id", 3], ["LIMIT", 11]]</span>
 =&gt; #&lt;ActiveRecord::Relation [
 #&lt;Article id: 2, title: "A2", content: "", status: "publish", created_at: "2021-02-16 14:08:34", updated_at: "2021-09-01 16:19:30", published_at: "2021-09-01 16:19:27"&gt;,
 #&lt;Article id: 3, title: "A3", content: "", status: "publish", created_at: "2021-02-16 14:13:15", updated_at: "2021-09-01 16:19:48", published_at: "2021-08-30 16:19:45"&gt;, 
 #&lt;Article id: 1, title: "A1", content: "", status: "publish", created_at: "2021-02-16 13:40:58", updated_at: "2021-02-28 03:35:34", published_at: nil&gt;]&gt;
</code></pre>
<p>Whether we use <code>COALESCE</code> in SQL statement or by ActiveRecord Query Interface above, we can get the sorting result as we expected!</p>
<ul>
<li><p>article2 (published_at: 2021-09-01 16:19:27) came first</p>
</li>
<li><p>article3(published_at: 2021-08-30 16:19:45)</p>
</li>
<li><p>article1(created_at: 2021-02-16 14:08:34) used <code>created_at</code> to order by</p>
</li>
</ul>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-coalesce/">https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-coalesce</a></p>
</li>
<li><p><a target="_blank" href="https://learnsql.com/blog/how-to-order-rows-with-nulls/?ref=lynnbright.com">https://learnsql.com/blog/how-to-order-rows-with-nulls</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/11003413/order-by-column1-if-column1-is-not-null-otherwise-order-by-column2?ref=lynnbright.com">https://stackoverflow.com/questions/11003413/order-by-column1-if-column1-is-not-null-otherwise-order-by-column2</a></p>
</li>
<li><p><a target="_blank" href="https://kb.objectrocket.com/postgresql/how-to-run-an-sql-file-in-postgres-846?ref=lynnbright.com">https://kb.objectrocket.com/postgresql/how-to-run-an-sql-file-in-postgres-846</a></p>
</li>
<li><p><a target="_blank" href="https://www.postgresql.org/docs/13/app-psql.html?ref=lynnbright.com">https://www.postgresql.org/docs/13/app-psql.html</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to use and test an AJAX request in Rails]]></title><description><![CDATA[What's AJAX?
AJAX (Asynchronous Javascript and XML) is a kind of technique that can send HTTP requests and exchange data with a server by Javascript. It's an important and practical technique to enhance the user experience, especially when we want to...]]></description><link>https://lynnbright.com/how-to-use-and-test-an-ajax-request-in-rails</link><guid isPermaLink="true">https://lynnbright.com/how-to-use-and-test-an-ajax-request-in-rails</guid><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Sun, 22 Aug 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/4Hg8LH9Hoxc/upload/b4687b42aa0653e4c896d7848487e56d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-whats-ajax">What's AJAX?</h3>
<p>AJAX (Asynchronous Javascript and XML) is a kind of technique that can send HTTP requests and exchange data with a server by Javascript. It's an important and practical technique to enhance the user experience, especially when we want to achieve the effect that updating the partial content and wouldn't like to reload the whole page.</p>
<h3 id="heading-how-to-send-an-ajax-request-in-rails">How to send an AJAX request in Rails</h3>
<p>Rails has built-in <a target="_blank" href="https://github.com/rails/jquery-ujs">Unobtrusive JavaScript</a> that has required in the <code>application.js</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//app/assets/javascripts/application.js</span>

<span class="hljs-comment">//= require jquery</span>
<span class="hljs-comment">//= require jquery_ujs</span>
</code></pre>
<p>Thanks to Unobtrusive JavaScript! We can just put something like <code>data-*</code> on the HTML DOM and some simple dynamic things can be implemented. (Read more about <a target="_blank" href="https://github.com/rails/jquery-ujs/wiki/Unobtrusive-scripting-support-for-jQuery-%28list-of-data-attributes%29">the list of data attributes</a>)</p>
<p>The most common one is <code>data-confirm</code>. After adding <code>data-confirm</code> like the example below, when a user clicks the <code>Delete</code>, a pop-up dialog with 'Are you sure to delete this event' texts will show up.</p>
<pre><code class="lang-ruby">&lt;%= link_to(
  <span class="hljs-string">'Delete'</span>, 
  event_path(event), 
  <span class="hljs-symbol">method:</span> <span class="hljs-symbol">:delete</span>, 
  <span class="hljs-symbol">data:</span> { <span class="hljs-symbol">confirm:</span> <span class="hljs-string">'Are you sure to delete this event?'</span> } 
 )
%&gt;
</code></pre>
<p>We can implement an AJAX request by the data attributes that Unobtrusive JavaScript has provided, too. Just like the example above, we just need to add <code>data-remote</code> on the target HTML DOM. After that, Rails will help us use AJAX to send the HTTP request.</p>
<p>For instance,</p>
<pre><code class="lang-ruby">&lt;%= link_to <span class="hljs-string">'Show the article'</span>, article_path(article), <span class="hljs-symbol">remote:</span> <span class="hljs-literal">true</span> %&gt;
</code></pre>
<p>Rails helper will generate HTML tags like:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/artciles/1"</span> <span class="hljs-attr">data-remote</span>=<span class="hljs-string">"true"</span>&gt;</span>an article<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<h3 id="heading-how-to-test-an-ajax-request-with-rspec">How to test an AJAX request with RSpec</h3>
<p>For a general GET request, the test subject might look like this:</p>
<pre><code class="lang-ruby">RSpec.describe ArticlesController, <span class="hljs-symbol">type:</span> <span class="hljs-symbol">:controller</span> <span class="hljs-keyword">do</span>
  describe <span class="hljs-string">'GET #show'</span> <span class="hljs-keyword">do</span>
    subject { get <span class="hljs-symbol">:show</span>, <span class="hljs-symbol">params:</span> params }

    let(<span class="hljs-symbol">:params</span>) { { <span class="hljs-symbol">id:</span> article.id } }

    it { is_expected.to have_http_status(<span class="hljs-symbol">:ok</span>) }
    it { is_expected.to render_template(<span class="hljs-symbol">:show</span>) }
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>To make an AJAX request to the show action using GET,</p>
<p>we have to add <code>xhr: true</code> to the subject (Rails version 5.0+):</p>
<pre><code class="lang-ruby">RSpec.describe ArticlesController, <span class="hljs-symbol">type:</span> <span class="hljs-symbol">:controller</span> <span class="hljs-keyword">do</span>
  describe <span class="hljs-string">'GET #show'</span> <span class="hljs-keyword">do</span>
    subject { get <span class="hljs-symbol">:show</span>, <span class="hljs-symbol">params:</span> params, <span class="hljs-symbol">xhr:</span> <span class="hljs-literal">true</span> }

    <span class="hljs-comment">#...</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>According to Rails <a target="_blank" href="https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/test_case.rb#L569">ActionController::TestCase</a>,</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># rails/actionpack/lib/action_controller/test_case.rb:569</span>

<span class="hljs-keyword">if</span> xhr
  @request.set_header <span class="hljs-string">"HTTP_X_REQUESTED_WITH"</span>, <span class="hljs-string">"XMLHttpRequest"</span>
  @request.fetch_header(<span class="hljs-string">"HTTP_ACCEPT"</span>) <span class="hljs-keyword">do</span> <span class="hljs-params">|k|</span>
  @request.set_header k, [Mime[<span class="hljs-symbol">:js</span>], Mime[<span class="hljs-symbol">:html</span>], Mime[<span class="hljs-symbol">:xml</span>], <span class="hljs-string">"text/xml"</span>, <span class="hljs-string">"*/*"</span>].join(<span class="hljs-string">", "</span>)
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>I'm curious if it is an AJAX request now, so I try to check it out by calling <code>request.headers["X-Requested-With"]</code> and <code>request.xhr?</code>.</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># rails console</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show</span></span>
=&gt;  binding.pry
    <span class="hljs-comment">#...</span>
  <span class="hljs-keyword">end</span>

 $ request.headers[<span class="hljs-string">"X-Requested-With"</span>]
 <span class="hljs-comment">#=&gt; "XMLHttpRequest"</span>

 $ request.xhr?
 <span class="hljs-comment">#=&gt; 0</span>
 <span class="hljs-comment"># means the value of headers["X-Requested-With"] is totally match "XMLHttpRequest" string</span>
</code></pre>
<p>The answer is yes! It's an AJAX request now.</p>
<p>The process of AJAX interacting with the server is by an <code>XMLHttpRequest</code> object. After setting <code>xhr: true</code> means the “X-Requested-With” header has contained “XMLHttpRequest” and tells the client to send the request by AJAX.</p>
<hr />
<h4 id="heading-reference">Reference</h4>
<ul>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started?ref=lynnbright.com">https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started</a></p>
</li>
<li><p><a target="_blank" href="https://guides.rubyonrails.org/working_with_javascript_in_rails.html?ref=lynnbright.com">https://guides.rubyonrails.org/working_with_javascript_in_rails.html</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/rails/jquery-ujs/wiki/Unobtrusive-scripting-support-for-jQuery-%28list-of-data-attributes%29?ref=lynnbright.com">https://github.com/rails/jquery-ujs/wiki/Unobtrusive-scripting-support-for-jQuery-%28list-of-data-attributes</a></p>
</li>
<li><p><a target="_blank" href="https://ihower.tw/rails/ajax.html?ref=lynnbright.com">https://ihower.tw/rails/ajax.html</a></p>
</li>
<li><p><a target="_blank" href="https://newbedev.com/rails-testing-xhr-with-post-data?ref=lynnbright.com">https://newbedev.com/rails-testing-xhr-with-post-data</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/test_case.rb?ref=lynnbright.com#L569">https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/test_case.rb#L569</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Understand `nil` in Ruby]]></title><description><![CDATA[What's nil?
nil is an instance of NilClass. It's a special Ruby object used to represent the absence of any value. And it also behaves like false when used in a conditional statement.
What's more, there is only one nil object, whose object_id is alwa...]]></description><link>https://lynnbright.com/understand-nil-in-ruby</link><guid isPermaLink="true">https://lynnbright.com/understand-nil-in-ruby</guid><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Fri, 13 Aug 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/q10VITrVYUM/upload/0bdbba39e8b1f25d564b6da3986ae360.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-whats-nil">What's <code>nil</code>?</h3>
<p><code>nil</code> is an instance of NilClass. It's a special Ruby object used to represent the absence of any value. And it also behaves like <code>false</code> when used in a conditional statement.</p>
<p>What's more, there is only one <code>nil</code> object, whose <code>object_id</code> is always 8 (in 64-bit Ruby).</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># irb</span>
$ <span class="hljs-literal">nil</span>.object_id
<span class="hljs-comment">#=&gt; 8</span>
</code></pre>
<h3 id="heading-lets-play-with-nil-now">Let's play with nil now.</h3>
<h3 id="heading-1-nil-and-nil">1. <code>nil</code> and <code>nil?</code></h3>
<p>In Ruby, NilClass inherits from Object, and both of NilClass and Object define <code>nil?</code> method.</p>
<ul>
<li><p>Only the object <code>nil</code> responds <code>true</code> to <code>nil?</code></p>
</li>
<li><p>Other objects, like <code>''</code> , <code>{}</code>, <code>[]</code> etc, responds <code>false</code> to <code>nil?</code></p>
</li>
</ul>
<pre><code class="lang-ruby"><span class="hljs-comment"># irb</span>
$ <span class="hljs-literal">nil</span>.<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; NilClass &lt; Object</span>

$ NilClass.instance_methods.<span class="hljs-keyword">include</span>?(<span class="hljs-symbol">:nil?</span>)
<span class="hljs-comment">#=&gt; true </span>

$ Object.instance_methods.<span class="hljs-keyword">include</span>?(<span class="hljs-symbol">:nil?</span>)
<span class="hljs-comment">#=&gt; true</span>
</code></pre>
<p>For example,</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># irb</span>
$ <span class="hljs-literal">nil</span>.<span class="hljs-literal">nil</span>?
<span class="hljs-comment">#=&gt; true</span>

$ <span class="hljs-string">''</span>.<span class="hljs-literal">nil</span>?
<span class="hljs-comment">#=&gt; false</span>

$ [].<span class="hljs-literal">nil</span>?
<span class="hljs-comment">#=&gt; false</span>

$ {}.<span class="hljs-literal">nil</span>?
<span class="hljs-comment">#=&gt; false</span>
</code></pre>
<h3 id="heading-2-nil-can-only-respond-to-blank-in-rails">2. <code>nil</code> can only respond to <code>blank?</code> in Rails.</h3>
<p>It's common to see <code>blank?</code> in the codebase. However, <code>blank?</code> is only defined in Rails library, not in Ruby.</p>
<p>We can see the different results when calling <code>nil.blank?</code> in irb and Rails console.</p>
<p>For example,</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># irb</span>
$ <span class="hljs-literal">nil</span>.blank?
<span class="hljs-comment">#=&gt; Traceback (most recent call last):</span>
<span class="hljs-comment">#        4: from /Users/yuchu/.rvm/rubies/ruby-2.6.6/bin/irb:23:in `&lt;main&gt;'</span>
<span class="hljs-comment">#        3: from /Users/yuchu/.rvm/rubies/ruby-2.6.6/bin/irb:23:in `load'</span>
<span class="hljs-comment">#        2: from /Users/yuchu/.rvm/rubies/ruby-2.6.6/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `&lt;top (required)&gt;'</span>
<span class="hljs-comment">#        1: from (irb):14</span>
<span class="hljs-comment">#NoMethodError (undefined method `blank?' for nil:NilClass)</span>
</code></pre>
<pre><code class="lang-ruby"><span class="hljs-comment"># rails console</span>
$ <span class="hljs-literal">nil</span>.blank?
<span class="hljs-comment">#=&gt; true</span>
</code></pre>
<h3 id="heading-3-nil-and-operator">3. <code>nil</code> and <code>!</code> , <code>!!</code> operator</h3>
<p><code>!</code> and <code>!!</code> are the operators to make sure the values return boolean.</p>
<pre><code class="lang-ruby">$ !<span class="hljs-literal">nil</span> 
<span class="hljs-comment">#=&gt; true</span>

$ !!<span class="hljs-literal">nil</span>
<span class="hljs-comment">#=&gt; false</span>
</code></pre>
<h3 id="heading-4-nil-and-ruby-if-modifier">4. <code>nil</code> and Ruby if modifier</h3>
<p>The syntax of Ruby <code>if</code> modifier looks like:</p>
<pre><code class="lang-ruby">code <span class="hljs-keyword">if</span> condition
</code></pre>
<blockquote>
<p><em>if</em> expressions are used for conditional execution. The values <em>false</em> and <em>nil</em> are false, and everything else is true.</p>
<p>Executes <em>code</em> if the <em>conditional</em> is true.</p>
</blockquote>
<p>For example,</p>
<pre><code class="lang-ruby">$ result = <span class="hljs-string">'Hello'</span>
$ note = { <span class="hljs-symbol">nickname:</span> <span class="hljs-string">'Jenny'</span> }
$ result = <span class="hljs-string">'Hello, Jane.'</span> <span class="hljs-keyword">if</span> <span class="hljs-literal">nil</span>
$ result
<span class="hljs-comment">#=&gt; 'Hello'</span>

$ result = <span class="hljs-string">'Hello, Jane.'</span> <span class="hljs-keyword">if</span> <span class="hljs-literal">false</span>
$ result 
<span class="hljs-comment">#=&gt; 'Hello'</span>

$ result = <span class="hljs-string">'Hello, Jane.'</span> <span class="hljs-keyword">if</span> <span class="hljs-literal">true</span>
$ result
<span class="hljs-comment">#=&gt; 'Hello, Jane.'</span>

$ result = <span class="hljs-string">'Hello, Bob.'</span> <span class="hljs-keyword">if</span> note[<span class="hljs-symbol">:non_existent_key</span>]
$ result
<span class="hljs-comment">#=&gt; 'Hello, Jane.'</span>


$ result = <span class="hljs-string">'Hello, Jenny.'</span> <span class="hljs-keyword">if</span> note[<span class="hljs-symbol">:nickname</span>]
$ result
<span class="hljs-comment">#=&gt; 'Hello, Jenny.'</span>
</code></pre>
<hr />
<p><code>nil</code> seems familiar, but there is something detailed worth learning.</p>
<p>Organizing the note helps me to correctly understand <code>nil</code>. It's helpful, especially when I need to read the code fastly.</p>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330">https://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330</a></p>
</li>
<li><p><a target="_blank" href="https://www.rubyguides.com/2018/01/ruby-nil/">https://www.rubyguides.com/2018/01/ruby-nil/</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/rubinius/rubinius/blob/master/core/nil.rb">https://github.com/rubinius/rubinius/blob/master/core/nil.rb</a></p>
</li>
<li><p><a target="_blank" href="https://www.tutorialspoint.com/ruby/ruby_if_else.htm">https://www.tutorialspoint.com/ruby/ruby_if_else.htm</a></p>
</li>
<li><p><a target="_blank" href="https://www.tutorialspoint.com/ruby/ruby_operators.htm">https://www.tutorialspoint.com/ruby/ruby_operators.htm</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[3 helpful methods in Rails console]]></title><description><![CDATA[Recently, I start reading Practicing Rails. I love the main point in chapter 1: Rails console is a good place to experiment with our ideas.
There are 3 tips to explore ideas through the Rails console I learned from Practicing Rails.
1. Use app object...]]></description><link>https://lynnbright.com/3-helpful-methods-in-rails-console</link><guid isPermaLink="true">https://lynnbright.com/3-helpful-methods-in-rails-console</guid><category><![CDATA[Ruby on Rails]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Thu, 05 Aug 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/7okkFhxrxNw/upload/f0c8f738854e1dca64108fbb84ee82b0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I start reading <a target="_blank" href="https://www.justinweiss.com/practicing-rails/">Practicing Rails</a>. I love the main point in chapter 1: <strong>Rails console is a good place to experiment with our ideas</strong>.</p>
<p>There are 3 tips to explore ideas through the Rails console I learned from Practicing Rails.</p>
<h3 id="heading-1-use-app-object">1. Use app object.</h3>
<p>Who is <code>app</code>?</p>
<pre><code class="lang-ruby">$ app.<span class="hljs-keyword">class</span>
<span class="hljs-comment">#=&gt; ActionDispatch::Integration::Session</span>

<span class="hljs-comment"># That means</span>
app = ActionDispatch::Integration::Session.new(Rails.application)
</code></pre>
<p>According to the [source code]($ app.class #=&gt; ActionDispatch::Integration::Session  # That means app = ActionDispatch::Integration::Session.new(Rails.application)),</p>
<blockquote>
<p>An instance of this class represents a set of requests and responses performed sequentially by a test process.</p>
</blockquote>
<p>And <code>ActionDispatch::Integration::Session</code> class includes the <code>ActionDispatch::Integration::RequestHelpers</code>. (Read more about <a target="_blank" href="https://github.com/rails/rails/blob/89361447e1491c8a756e46e94df70d82595d1534/actionpack/lib/action_dispatch/testing/integration.rb#L12">this module</a>)</p>
<p>So, we can use <code>app</code> to perform HTTP requests:</p>
<pre><code class="lang-ruby">$ app.get(<span class="hljs-string">'http://localhost:3000/articles/1'</span>)
<span class="hljs-comment"># Started GET "/articles/1" for 127.0.0.1 at 2021-07-07 15:14:08 +0800</span>
<span class="hljs-comment"># Processing by ArticlesController#show as HTML</span>
<span class="hljs-comment">#  Parameters: {"id"=&gt;"1"}</span>
<span class="hljs-comment">#  Article Load (0.6ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]</span>
<span class="hljs-comment">#  Rendering articles/show.html.erb within layouts/application</span>
<span class="hljs-comment">#  Rendered articles/show.html.erb within layouts/application (Duration: 2.7ms | Allocations: 344)</span>
<span class="hljs-comment">#  Rendered layouts/_header.html.erb (Duration: 0.4ms | Allocations: 145)</span>
<span class="hljs-comment">#  Rendered layouts/_footer.html.erb (Duration: 0.5ms | Allocations: 91)</span>
<span class="hljs-comment"># Completed 200 OK in 17ms (Views: 13.3ms | ActiveRecord: 0.6ms | Allocations: 4199)</span>

<span class="hljs-comment">#=&gt; 200</span>


$ puts app.response.body.first(<span class="hljs-number">200</span>)
<span class="hljs-comment"># &lt;!DOCTYPE html&gt;</span>
<span class="hljs-comment"># &lt;html&gt;</span>
<span class="hljs-comment">#   &lt;head&gt;</span>
<span class="hljs-comment">#    &lt;title&gt;Lynn's Blog&lt;/title&gt;</span>
<span class="hljs-comment">#    &lt;meta name="csrf-param" content="</span>
<span class="hljs-comment"># =&gt; nil</span>
</code></pre>
<p>What's more, we can use <code>app</code> to get routes.</p>
<pre><code class="lang-ruby">$ article = Article.create(<span class="hljs-symbol">title:</span> <span class="hljs-string">'beautiful_article'</span>)
$ app.article_path(article)
<span class="hljs-comment">#=&gt; '/articles/1'</span>
</code></pre>
<hr />
<h3 id="heading-2-use-helper-object-to-preview-html-tags-or-other-return-values">2. Use helper object to preview HTML tags or other return values.</h3>
<p>For example,</p>
<pre><code class="lang-ruby">$ helper.link_to(<span class="hljs-string">'Hello world!'</span>, <span class="hljs-string">'https://www.example.com'</span>)
<span class="hljs-comment">#=&gt; "&lt;a href=\"https://www.example.com\"&gt;Hello world!&lt;/a&gt;"</span>
</code></pre>
<p>If you find out that you get the <code>undefined method</code> error message when trying to call a custom <code>helper</code>. It might mean the module hasn't been included.</p>
<pre><code class="lang-ruby">$ helper.your_custom_helper_method
<span class="hljs-comment">#=&gt; NoMethodError: undefined method `your_custom_helper_method' for #&lt;ActionView::Base:0x00007fe53d1cf140&gt;</span>
</code></pre>
<p>It's good timing to check <code>config/application.rb</code>, if the setting below is <code>false</code>.</p>
<pre><code class="lang-plaintext">config.action_controller.include_all_helpers = false
</code></pre>
<p>If you just want to check the return value of this custom helper method and don't want to change the setting above, we can include this helper module first:</p>
<pre><code class="lang-ruby">$ <span class="hljs-keyword">include</span> Admin::ProjectsHelper
<span class="hljs-comment">#=&gt; Object &lt; BasicObject</span>

$ helper.your_custom_helper_method
<span class="hljs-comment">#=&gt; 'hi, how are you?'</span>
</code></pre>
<hr />
<h3 id="heading-3-use-a-special-variable">3. Use a special variable <code>_</code>.</h3>
<p>The result of the last line we ran in the console is automatically saved in a variable named <code>_</code>.</p>
<p>For example,</p>
<pre><code class="lang-ruby">$ Article.new
<span class="hljs-comment">#=&gt; #&lt;Article id: nil, title: "", content: "", cover: nil, status: "draft", created_at: nil, updated_at: nil&gt;</span>

$ <span class="hljs-number">_</span>
<span class="hljs-comment">#=&gt; #&lt;Article id: nil, title: "", content: "", cover: nil, status: "draft", created_at: nil, updated_at: nil&gt;</span>

<span class="hljs-comment"># Assume `title` attribute cannot be blank</span>
$ <span class="hljs-number">_</span>.valid?
<span class="hljs-comment">#=&gt; false</span>

$ <span class="hljs-number">_</span>
<span class="hljs-comment">#=&gt; false</span>

$ <span class="hljs-number">_</span>.errors.messages
<span class="hljs-comment">#=&gt; Traceback (most recent call last):</span>
<span class="hljs-comment">#       2: from (irb):46</span>
<span class="hljs-comment">#       1: from (irb):47:in `rescue in irb_binding'</span>
<span class="hljs-comment"># NoMethodError (undefined method `errors' for #&lt;NoMethodError: undefined method `error' for false:FalseClass&gt;)</span>
</code></pre>
<p>Next time, if we forget to assign a variable, we can just pick it up to use. :P</p>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://www.justinweiss.com/practicing-rails/">https://www.justinweiss.com/practicing-rails/</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/rails/rails/blob/89361447e1491c8a756e46e94df70d82595d1534/actionpack/lib/action_dispatch/testing/integration.rb">https://github.com/rails/rails/blob/89361447e1491c8a756e46e94df70d82595d1534/actionpack/lib/action_dispatch/testing/integration.rb</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[RSpec - Use shared_examples to avoid duplicate test examples]]></title><description><![CDATA[It's common to see a before_action method that need executing in different controller actions. At the same time, when writing RSpec tests for these actions, it's easily to write down context blocks whose test examples are almost the same, and only a ...]]></description><link>https://lynnbright.com/rspec-use-sharedexamples-to-avoid-duplicate-test-examples</link><guid isPermaLink="true">https://lynnbright.com/rspec-use-sharedexamples-to-avoid-duplicate-test-examples</guid><category><![CDATA[Ruby on Rails]]></category><category><![CDATA[#rspec]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Sun, 01 Aug 2021 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/ylveRpZ8L1s/upload/028b28b9ae39a73c2418f4450fe22bbe.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It's common to see a <code>before_action</code> method that need executing in different controller actions. At the same time, when writing RSpec tests for these actions, it's easily to write down context blocks whose test examples are almost the same, and only a <code>let</code> declaration is different.</p>
<p>The code might look like this:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="71ac3641db8d7dd33ef14d98ed1fa449"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/lynnbright/71ac3641db8d7dd33ef14d98ed1fa449" class="embed-card">https://gist.github.com/lynnbright/71ac3641db8d7dd33ef14d98ed1fa449</a></div><p> </p>
<p>Though these test examples seem readable, there are some shortcomings:</p>
<ol>
<li><p>When the rule of <code>#setup_discount</code> was changed, we need to revise <code>when assigns @discount</code> test example groups of <code>FruitContrller#index</code> and <code>FruitController#show</code> at the same time. Imagine when there are 10 controllers and all of them also need to execute <code>#setup_discount</code> which means we have to revise the same thing 10 times. horrible...</p>
</li>
<li><p>It seems not DRY.</p>
</li>
</ol>
<p>Fortunately, RSpec provides <code>shared_examples</code> for us to solve the duplicate test examples problem.</p>
<hr />
<h3 id="heading-how-to-use-sharedexamples">How to use <code>shared_examples</code></h3>
<p>Take <code>FruitContrller#index</code> and <code>FruitController#show</code> RSpec tests for example.</p>
<ol>
<li>Add a new shared_examples file.</li>
</ol>
<p>Before adding this new file, we need to check where to put this file so that it will be required automatically before running tests.</p>
<p>In my project, I follow the convention and put this file at:</p>
<p><code>spec/support/controllers/shared_examples/expected_discount_examples.rb</code></p>
<pre><code class="lang-ruby"><span class="hljs-comment"># spec/spec_helper.rb</span>

Dir[<span class="hljs-string">"./spec/support/**/*.rb"</span>].sort.each { <span class="hljs-params">|f|</span> <span class="hljs-keyword">require</span> f }
</code></pre>
<p>2. Pick up the duplicate part.</p>
<p>For example,</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># index request test examples</span>
context <span class="hljs-string">'when assigns @discount'</span> <span class="hljs-keyword">do</span>
  let(<span class="hljs-symbol">:super_market</span>) { create(<span class="hljs-symbol">:super_market</span>) }
  let(<span class="hljs-symbol">:user</span>) { create(<span class="hljs-symbol">:user</span>, <span class="hljs-symbol">special_pass_available:</span> special_pass_available? }

  <span class="hljs-comment">#...</span>

  context <span class="hljs-string">'when current_user owns special pass'</span> <span class="hljs-keyword">do</span>     
    let(<span class="hljs-symbol">:special_pass_available?</span>) { <span class="hljs-literal">true</span> }
    it { expect(assigns(<span class="hljs-symbol">:discount</span>)).to eq(<span class="hljs-number">0</span>.<span class="hljs-number">5</span>) }
  <span class="hljs-keyword">end</span>

  context <span class="hljs-string">'when current_user does not own any special pass'</span> <span class="hljs-keyword">do</span>
    let(<span class="hljs-symbol">:special_pass_available?</span>) { <span class="hljs-literal">false</span> }

    it { expect(assigns(<span class="hljs-symbol">:discount</span>)).to eq(<span class="hljs-number">0</span>) }
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

<span class="hljs-comment"># show request test examples</span>
context <span class="hljs-string">'when assigns @discount'</span> <span class="hljs-keyword">do</span>
  let(<span class="hljs-symbol">:super_market</span>) { create(<span class="hljs-symbol">:super_market</span>) }
  let(<span class="hljs-symbol">:user</span>) { create(<span class="hljs-symbol">:user</span>, <span class="hljs-symbol">special_pass_available:</span> special_pass_available? }

  <span class="hljs-comment">#...</span>

  context <span class="hljs-string">'when current_user owns special pass'</span> <span class="hljs-keyword">do</span>        
    let(<span class="hljs-symbol">:special_pass_available?</span>) { <span class="hljs-literal">true</span> }

    it { expect(assigns(<span class="hljs-symbol">:discount</span>)).to eq(<span class="hljs-number">0</span>.<span class="hljs-number">5</span>) }
  <span class="hljs-keyword">end</span>

  context <span class="hljs-string">'when current_user does not own any special pass'</span> <span class="hljs-keyword">do</span>
    let(<span class="hljs-symbol">:special_pass_available?</span>) { <span class="hljs-literal">false</span> }

    it { expect(assigns(<span class="hljs-symbol">:discount</span>)).to eq(<span class="hljs-number">0</span>) }
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>3. Pick up the different parts.</p>
<p>For example,</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># index request test examples</span>
context <span class="hljs-string">'when assigns @discount'</span> <span class="hljs-keyword">do</span>
  <span class="hljs-comment">#...</span>

  before { index_request }

  <span class="hljs-comment">#...</span>
<span class="hljs-keyword">end</span>

<span class="hljs-comment"># show request test examples</span>
context <span class="hljs-string">'when assigns @discount'</span> <span class="hljs-keyword">do</span>
  <span class="hljs-comment">#...</span>

  before { show_request }

  <span class="hljs-comment">#...</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>4. Put the duplicate part in the shared_examples file.</p>
<pre><code class="lang-ruby">RSpec.shared_examples <span class="hljs-string">'an expected @fruit'</span> <span class="hljs-keyword">do</span>
  let(<span class="hljs-symbol">:super_market</span>) { create(<span class="hljs-symbol">:super_market</span>) }
  let(<span class="hljs-symbol">:user</span>) { create(<span class="hljs-symbol">:user</span>, <span class="hljs-symbol">special_pass_available:</span> special_pass_available? }

  <span class="hljs-comment">#...</span>

  context <span class="hljs-string">'when current_user owns special pass'</span> <span class="hljs-keyword">do</span>  
    let(<span class="hljs-symbol">:special_pass_available?</span>) { <span class="hljs-literal">true</span> }

    it { expect(assigns(<span class="hljs-symbol">:discount</span>)).to eq(<span class="hljs-number">0</span>.<span class="hljs-number">5</span>) }
  <span class="hljs-keyword">end</span>

  context <span class="hljs-string">'when current_user does not own any special pass'</span> <span class="hljs-keyword">do</span>
    let(<span class="hljs-symbol">:special_pass_available?</span>) { <span class="hljs-literal">false</span> }

    it { expect(assigns(<span class="hljs-symbol">:discount</span>)).to eq(<span class="hljs-number">0</span>) }
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>5. Setup <code>request</code> variable for the different part</p>
<pre><code class="lang-ruby">RSpec.shared_examples <span class="hljs-string">'an expected @fruit'</span> <span class="hljs-keyword">do</span>
  <span class="hljs-comment">#...</span>

  before { request }

  <span class="hljs-comment">#...</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>6. Include the shared_examples into the test file.</p>
<p>RSpec <a target="_blank" href="https://relishapp.com/rspec/rspec-core/docs/example-groups/shared-examples">official documentation</a> provides four ways to include:</p>
<pre><code class="lang-ruby">include_examples <span class="hljs-string">"name"</span>      <span class="hljs-comment"># include the examples in the current context</span>
it_behaves_like <span class="hljs-string">"name"</span>       <span class="hljs-comment"># include the examples in a nested context</span>
it_should_behave_like <span class="hljs-string">"name"</span> <span class="hljs-comment"># include the examples in a nested context</span>
matching metadata            <span class="hljs-comment"># include the examples in the current context</span>
</code></pre>
<p>I need to pass different request actions which are declared in <code>subject</code> or <code>let</code> into the shared group, so I use <code>it_behaves_like</code> to include it.</p>
<p>&lt;!--kg-card-begin: html--&gt; &lt;script src="https://gist.github.com/lynnbright/aadb8c014ce5eca30a9a2a721e3c4cab.js"&gt;&lt;/script&gt; &lt;!--kg-card-end: html--&gt;</p>
<p>After using <code>shared_examples</code>, we solve two problems:</p>
<ul>
<li><p>When the rule of <code>#setup_discount</code> changes, all we need to do is to revise the shared_examples file and make a minor adjustment to <code>let</code> declaration.</p>
</li>
<li><p>It seems DRY now.</p>
</li>
</ul>
<hr />
<p>Although <code>include_examples</code> didn't come in handy this time, there is something worth noting.</p>
<p>According to the official documentation, there is a warning message:</p>
<blockquote>
<p><strong>WARNING:</strong> When you include parameterized examples in the current context multiple times, you may override previous method definitions and last declaration wins.</p>
<p>To prevent this kind of subtle error a warning is emitted if you declare multiple methods with the same name in the same context. Should you get this warning the simplest solution is to replace <code>include_examples</code> with <code>it_behaves_like</code>, <strong>in this way method overriding is avoided because of the nested context created by</strong> <code>it_behaves_like</code></p>
</blockquote>
<p>Read the detailed code sample: <a target="_blank" href="https://relishapp.com/rspec/rspec-core/v/3-10/docs/example-groups/shared-examples#aliasing-%60it-should-behave-like%60-to-%60it-has-behavior%60">here</a></p>
<hr />
<h3 id="heading-reference">Reference</h3>
<ul>
<li><p><a target="_blank" href="https://relishapp.com/rspec/rspec-core/v/3-10/docs/example-groups/shared-examples">https://relishapp.com/rspec/rspec-core/v/3-10/docs/example-groups/shared-examples</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/rubocop/rspec-style-guide#shared-examples">https://github.com/rubocop/rspec-style-guide#shared-examples</a></p>
</li>
<li><p><a target="_blank" href="https://www.betterspecs.org/#shared">https://www.betterspecs.org/#shared</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Before adding a new validation, one thing you should notice]]></title><description><![CDATA[When we develop a new feature, it's common to add a new column that needs some validations in the model. So, we might write something like this:
class Book < ApplicationRecord
  #...
  validates :barcode, presence: true
end

To increase the test cove...]]></description><link>https://lynnbright.com/before-adding-a-new-validation-one-thing-you-should-notice</link><guid isPermaLink="true">https://lynnbright.com/before-adding-a-new-validation-one-thing-you-should-notice</guid><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Sat, 24 Jul 2021 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/FHnnjk1Yj7Y/upload/695349c2d082f1ec9450abec8acc1137.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When we develop a new feature, it's common to add a new column that needs some validations in the model. So, we might write something like this:</p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span> &lt; ApplicationRecord</span>
  <span class="hljs-comment">#...</span>
  validates <span class="hljs-symbol">:barcode</span>, <span class="hljs-symbol">presence:</span> <span class="hljs-literal">true</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>To increase the test coverage, adding the test example is necessary:</p>
<pre><code class="lang-ruby">RSpec.describe Book, <span class="hljs-symbol">type:</span> <span class="hljs-symbol">:model</span> <span class="hljs-keyword">do</span>
  <span class="hljs-comment">#...</span>
  it { is_expected.to validate_presence_of(<span class="hljs-symbol">:barcode</span>) }
<span class="hljs-keyword">end</span>
</code></pre>
<p>Everything seems to make sense. All the test examples have passed.</p>
<p>However, something wrong happened after deploying to the production. Rollbar showed warnings that were related to this validation. Some Book records failed to update.</p>
<p>At that time, I suddenly realized I need to think more about 'adding a new validation'.</p>
<h3 id="heading-how-to-avoid-the-same-situation">How to avoid the same situation</h3>
<p>The first thing is to ask:</p>
<blockquote>
<p>After adding this new validation, can old records pass this new validation when they need updating something?</p>
</blockquote>
<p>If the answer is no, that means there are two things we need to think about:</p>
<ol>
<li><p>When does this validation need executing? Whenever a record is updated? Or, the validation can be executed only when the column value to an old record is different from before?</p>
</li>
<li><p>What if the new column has to be <code>presence: true</code> ? My opinion is that we only validate the new record. Because neither should we ask users to update the value themselves, nor inserting the value for them.</p>
</li>
</ol>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span> &lt; ApplicationRecord</span>
  <span class="hljs-comment">#...</span>
  validates <span class="hljs-symbol">:barcode</span>, <span class="hljs-symbol">presence:</span> <span class="hljs-literal">true</span>, <span class="hljs-symbol">if:</span> <span class="hljs-symbol">:new_record?</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>After adding the validation, we should add the test examples to make sure the timing of the validation execution is as we expect.</p>
<hr />
<p>Thanks for this experience to remind me:</p>
<blockquote>
<p>Even though adding a validation is a simple thing, it's important to estimate if it will cause side effects.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Git - There are too many unreachable loose objects]]></title><description><![CDATA[To Reproduce:

git cm 'some_message'

commit successfully, but git showed the message below:


error: The last gc run reported the following. Please correct the root
cause and remove gc.log.
Automatic cleanup will not be performed until the file is r...]]></description><link>https://lynnbright.com/git-there-are-too-many-unreachable-loose-objects</link><guid isPermaLink="true">https://lynnbright.com/git-there-are-too-many-unreachable-loose-objects</guid><category><![CDATA[Git]]></category><dc:creator><![CDATA[Lynn Chang]]></dc:creator><pubDate>Fri, 23 Jul 2021 16:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/gySMaocSdqs/upload/cdca1602993ae36e2e07ea777437c4f0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-to-reproduce">To Reproduce:</h3>
<ul>
<li><p><code>git cm 'some_message'</code></p>
</li>
<li><p>commit successfully, but git showed the message below:</p>
</li>
</ul>
<pre><code class="lang-plaintext">error: The last gc run reported the following. Please correct the root
cause and remove gc.log.
Automatic cleanup will not be performed until the file is removed.
warning: There are too many unreachable loose objects; run 'git prune'
to remove them.
</code></pre>
<h3 id="heading-why-git-shows-this-error-message">Why git shows this error message?</h3>
<blockquote>
<p><em>You are seeing this error because you have too many dangling commits for git to automatically clean up.</em></p>
</blockquote>
<h3 id="heading-what-is-dangling-commit-amp-dangling-blob">What is "dangling commit" &amp; "dangling blob"?</h3>
<p>Dangling objects exist but they are never directly used.</p>
<ul>
<li><strong>Dangling blob</strong></li>
</ul>
<p>A change that made it to the staging area/index but never got committed.</p>
<ul>
<li><strong>Dangling commit</strong></li>
</ul>
<p>A commit isn’t directly linked to any child commit, branch, tag, or other references.</p>
<p>(Information from: <a target="_blank" href="https://stackoverflow.com/questions/18514659/git-what-is-a-dangling-commit-blob-and-where-do-they-come-from">Stack overflow</a>)</p>
<h3 id="heading-what-will-dangling-objects-have-an-influence-on">What will “dangling objects” have an influence on?</h3>
<p>Actually, the worst situation is dangling objects take up too much space of the hard disk.</p>
<h3 id="heading-how-to-solve-the-too-many-dangling-objects-problem">How to solve the "too many dangling objects" problem?</h3>
<ol>
<li><code>git fsck</code></li>
</ol>
<p>This will verify the connectivity, validity of the object and list those dangling objects if they exist.</p>
<p>2. <code>git gc --prune=now</code></p>
<ul>
<li><code>git prune</code></li>
</ul>
<p>This will remove dangling objects.</p>
<ul>
<li><code>git gc</code></li>
</ul>
<blockquote>
<p><em>-prune=&lt;date&gt; Prune loose objects older than date (default is 2 weeks ago, overridable by the config variable gc.pruneExpire). — prune=now prunes loose objects regardless of their age and increases the risk of corruption if another process is writing to the repository concurrently; see “NOTES” below. — prune is on by default.</em></p>
</blockquote>
<hr />
<p>Reference:</p>
<ul>
<li><p><a target="_blank" href="https://community.perforce.com/s/article/16023">https://community.perforce.com/s/article/16023</a></p>
</li>
<li><p><a target="_blank" href="https://www.cnblogs.com/dylancao/p/6625431.html">https://www.cnblogs.com/dylancao/p/6625431.html</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/18514659/git-what-is-a-dangling-commit-blob-and-where-do-they-come-from">https://stackoverflow.com/questions/18514659/git-what-is-a-dangling-commit-blob-and-where-do-they-come-from</a></p>
</li>
<li><p><a target="_blank" href="https://git-scm.com/docs/git-fsck">https://git-scm.com/docs/git-fsck</a></p>
</li>
<li><p><a target="_blank" href="https://git-scm.com/docs/git-gc">https://git-scm.com/docs/git-gc</a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>