<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
  <title>BigBinary Blog: Rails 6</title>
  <subtitle>Deep technical writing on Ruby on Rails, performance, scaling, monitoring and engineering.</subtitle>
  <link rel="self" type="application/atom+xml" href="https://www.bigbinary.com/blog/categories/rails-6/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/categories/rails-6"/>
  <id>https://www.bigbinary.com/blog/categories/rails-6</id>
  <updated>2020-09-01T00:00:00.000Z</updated>
  <author>
    <name>BigBinary</name>
    <uri>https://www.bigbinary.com/</uri>
  </author>
  <icon>https://www.bigbinary.com/favicon.ico</icon>
  <logo>https://www.bigbinary.com/images/bigbinary_square_big_logo.png</logo>
  <rights>Copyright 2020 Big Binary LLC</rights>
  <generator uri="https://nextjs.org">Next.js</generator>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds support to persist timezones of Active Job]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-add-timezone-support-in-active-job"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-add-timezone-support-in-active-job.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-add-timezone-support-in-active-job</id>
      <published>2020-09-01T00:00:00.000Z</published>
      <updated>2020-09-01T00:00:00.000Z</updated>
      <author>
        <name>Chetan Gawai</name>
        <uri>https://www.bigbinary.com/blog/authors/chetangawai</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-add-timezone-support-in-active-job.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 now records current timezone of Active Job]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-add-timezone-support-in-active-job"><![CDATA[<p>When a job is enqueued in Rails 6 using Active Job, the current timezone of a
job is <a href="https://github.com/rails/rails/pull/32085/">preserved</a> and then this
preserved timezone is restored when the job is finished executing.</p>
<p>Let's take an example of sale at Amazon.</p>
<p>Amazon would like to remind users across different timezones about its upcoming
sale by sending an email. This task of sending a reminder would be processed as
a background job.</p>
<p><b>Before:</b></p>
<p>Before Rails 6, we had to pass timezone explicitly to the <code>perform</code> method of
the job as shown below.</p>
<pre><code class="language-ruby">timezone = &quot;Eastern Time (US &amp; Canada)&quot;

AmazonSaleJob.perform_later(Time.now, timezone)

class AmazonSaleJob &lt; ApplicationJob
  queue_as :default

  def perform(time, timezone)

    time = time.in_time_zone(timezone)
    sale_start_time = localtime(2020, 12, 24)

    if time &gt;= sale_start_time
      puts &quot;Sale has started!&quot;
      #Send an email stating Sale has started
    else
      sale_starts_in = (sale_start_time - time).div(3600)
      puts &quot;Hang on! Sale will start in #{sale_starts_in} hours&quot;
      #Send an email stating sales starts in sale_starts_in hours
     end
  end

  private

    def localtime(*args)
      Time.zone ? Time.zone.local(*args) : Time.utc(*args)
    end
end

</code></pre>
<p><b>After:</b></p>
<p>After the changes in Rails 6, passing timezone to Job is now taken care of by
Rails.</p>
<pre><code class="language-ruby">timezone = &quot;Eastern Time (US &amp; Canada)&quot;

Time.use_zone(timezone) do
  AmazonSaleJob.perform_later(Time.zone.now)
end

class AmazonSaleJob &lt; ApplicationJob
  queue_as :default

  def perform(time)
    sale_start_time = localtime(2020, 12, 24)

    if time &gt;= sale_start_time
      puts &quot;Sale has started!&quot;
      #Send an email stating Sale has started
    else
      sale_starts_in = (sale_start_time - time).div(3600)
      puts &quot;Hang on! Sale will start in #{sale_starts_in} hours&quot;
      #Send an email stating sales starts in sale_starts_in hours
     end
   end

  private

    def localtime(*args)
      Time.zone ? Time.zone.local(*args) : Time.utc(*args)
    end
end

</code></pre>
<p>Rails 6 also propagates timezone to all the subsequent nested jobs.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds including & excluding method on Enumerables]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-array-including-excluding-and-enumerable-including-excluding"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-array-including-excluding-and-enumerable-including-excluding.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-array-including-excluding-and-enumerable-including-excluding</id>
      <published>2020-08-18T00:00:00.000Z</published>
      <updated>2020-08-18T00:00:00.000Z</updated>
      <author>
        <name>Akhil Gautam</name>
        <uri>https://www.bigbinary.com/blog/authors/akhilgautam</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-array-including-excluding-and-enumerable-including-excluding.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds Array#including/excluding and Enumerable#including/excluding]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-array-including-excluding-and-enumerable-including-excluding"><![CDATA[<p>Rails 6 added <code>including</code> and <code>excluding</code> on Array and Enumerable.</p>
<h4>Array#including and Enumerable#including</h4>
<p><code>including</code> can be used to extend a collection in a more object oriented way. It
does not mutate the original collection but returns a new collection which is
the concatenation of the given collections.</p>
<pre><code class="language-ruby">
# multiple arguments can be passed to including

&gt; &gt; [1, 2, 3].including(4, 5)
&gt; &gt; =&gt; [1, 2, 3, 4, 5]

# another enumerable can also be passed to including

&gt; &gt; [1, 2, 3].including([4, 5])
&gt; &gt; =&gt; [1, 2, 3, 4, 5]

&gt; &gt; %i(apple orange).including(:banana)
&gt; &gt; =&gt; [:apple, :orange, :banana]

# return customers whose country_code is IN along with the prime customers

&gt; &gt; Customer.where(country_code: &quot;IN&quot;).including(Customer.where(prime: true))

</code></pre>
<h4>Array#excluding and Enumerable#excluding</h4>
<p>It returns a copy of the enumerable excluding the given collection.</p>
<pre><code class="language-ruby">
# multiple arguments can be passed to including

&gt; &gt; [11, 22, 33, 44].excluding([22, 33])
&gt; &gt; =&gt; [11, 44]

&gt; &gt; %i(ant bat cat).excluding(:bat)
&gt; &gt; =&gt; [:ant, :cat]

# return all prime customers except those who haven't added their phone

&gt; &gt; Customer.where(prime: true).excluding(Customer.where(phone: nil))

</code></pre>
<p><code>Array#excluding and Enumerable#excluding</code> replaces the already existing method
<code>without</code> which in Rails 6 is now aliased to <code>excluding</code>.</p>
<pre><code class="language-ruby">
&gt; &gt; [11, 22, 33, 44].without([22, 33])
&gt; &gt; =&gt; [11, 44]

</code></pre>
<p><code>excluding</code> and <code>including</code> helps to shrink or extend a collection without using
any operator.</p>
<p>Check out the
<a href="https://github.com/rails/rails/commit/bfaa3091c3c32b5980a614ef0f7b39cbf83f6db3">commit</a>
for more details on this.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 fixes after_commit callback invocation bug]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-fixes-a-bug-where-after_commit-callbacks-are-called-on-failed-update-in-a-transaction-block"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-fixes-a-bug-where-after_commit-callbacks-are-called-on-failed-update-in-a-transaction-block.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-fixes-a-bug-where-after_commit-callbacks-are-called-on-failed-update-in-a-transaction-block</id>
      <published>2020-02-25T00:00:00.000Z</published>
      <updated>2020-02-25T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-fixes-a-bug-where-after_commit-callbacks-are-called-on-failed-update-in-a-transaction-block.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 fixes a bug where after_commit callbacks are called on failed update in a transaction block]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-fixes-a-bug-where-after_commit-callbacks-are-called-on-failed-update-in-a-transaction-block"><![CDATA[<p>Rails 6 fixes a <a href="https://github.com/rails/rails/issues/29747">bug</a> where
<a href="https://apidock.com/rails/ActiveRecord/Transactions/ClassMethods/after_commit">after_commit</a>
callbacks are called on failed update in a transaction block.</p>
<p>Let's checkout the bug in Rails 5.2 and the fix in Rails 6.</p>
<h4>Rails 5.2</h4>
<p>Let's define an
<a href="https://apidock.com/rails/ActiveRecord/Transactions/ClassMethods/after_commit">after_commit</a>
callback in <code>User</code> model and try updating an invalid user object in a
transaction block.</p>
<pre><code class="language-ruby">&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   validates :name, :email, presence: true
&gt;&gt;
&gt;&gt;   after_commit :show_success_message
&gt;&gt;
&gt;&gt;   private
&gt;&gt;
&gt;&gt;     def show_success_message
&gt;&gt;       p 'User has been successfully saved into the database.'
&gt;&gt;     end
&gt;&gt; end

=&gt; :show_success_message

&gt;&gt; user = User.create(name: 'Jon Snow', email: 'jon@bigbinary.com')
begin transaction
User Create (0.8ms)  INSERT INTO &quot;users&quot; (&quot;name&quot;, &quot;email&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES (?, ?, ?, ?)  [[&quot;name&quot;, &quot;Jon Snow&quot;], [&quot;email&quot;, &quot;jon@bigbinary.com&quot;], [&quot;created_at&quot;, &quot;2019-07-14 15:35:33.517694&quot;], [&quot;updated_at&quot;, &quot;2019-07-14 15:35:33.517694&quot;]]
commit transaction
&quot;User has been successfully saved into the database.&quot;

=&gt; #&lt;User id: 1, name: &quot;Jon Snow&quot;, email: &quot;jon@bigbinary.com&quot;, created_at: &quot;2019-07-14 15:35:33&quot;, updated_at: &quot;2019-07-14 15:35:33&quot;&gt;

&gt;&gt; User.transaction do
&gt;&gt;   user.email = nil
&gt;&gt;   p user.valid?
&gt;&gt;   user.save
&gt;&gt; end
begin transaction
false
commit transaction
&quot;User has been successfully saved into the database.&quot;

=&gt; false
</code></pre>
<p>As we can see here, that that the after_commit callback <code>show_success_message</code>
was called even if object was never saved in the transaction.</p>
<h4>Rails 6.0.0.rc1</h4>
<p>Now, let's try the same thing in Rails 6.</p>
<pre><code class="language-ruby">&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   validates :name, :email, presence: true
&gt;&gt;
&gt;&gt;   after_commit :show_success_message
&gt;&gt;
&gt;&gt;   private
&gt;&gt;
&gt;&gt;     def show_success_message
&gt;&gt;       p 'User has been successfully saved into the database.'
&gt;&gt;     end
&gt;&gt; end

=&gt; :show_success_message

&gt;&gt; user = User.create(name: 'Jon Snow', email: 'jon@bigbinary.com')
SELECT sqlite_version(*)
begin transaction
User Create (1.0ms)  INSERT INTO &quot;users&quot; (&quot;name&quot;, &quot;email&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES (?, ?, ?, ?)  [[&quot;name&quot;, &quot;Jon Snow&quot;], [&quot;email&quot;, &quot;jon@bigbinary.com&quot;], [&quot;created_at&quot;, &quot;2019-07-14 15:40:54.022045&quot;], [&quot;updated_at&quot;, &quot;2019-07-14 15:40:54.022045&quot;]]
commit transaction
&quot;User has been successfully saved into the database.&quot;

=&gt; #&lt;User id: 1, name: &quot;Jon Snow&quot;, email: &quot;jon@bigbinary.com&quot;, created_at: &quot;2019-07-14 15:40:54&quot;, updated_at: &quot;2019-07-14 15:40:54&quot;&gt;

&gt;&gt; User.transaction do
&gt;&gt;   user.email = nil
&gt;&gt;   p user.valid?
&gt;&gt;   user.save
&gt;&gt;   end
false

=&gt; false
</code></pre>
<p>Now, we can see that after_commit callback was never called if the object was
not saved.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/issues/29747">issue</a> and
the <a href="https://github.com/rails/rails/pull/32185">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds rails db:prepare to migrate or setup a database]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-rails-db-prepare-to-migrate-or-setup-a-database"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-rails-db-prepare-to-migrate-or-setup-a-database.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-rails-db-prepare-to-migrate-or-setup-a-database</id>
      <published>2019-12-10T00:00:00.000Z</published>
      <updated>2019-12-10T00:00:00.000Z</updated>
      <author>
        <name>Akhil Gautam</name>
        <uri>https://www.bigbinary.com/blog/authors/akhilgautam</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-rails-db-prepare-to-migrate-or-setup-a-database.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds rails db:prepare to migrate or setup a database if it doesn't exist]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-rails-db-prepare-to-migrate-or-setup-a-database"><![CDATA[<p>Rails 6 adds rails db:prepare to migrate or setup a database if it doesn't
exist.</p>
<p>Before Rails 6, we had to run the following tasks to set up the database.</p>
<pre><code class="language-ruby"># create the database
rails db:create

# run the migrations
rails db:migrate

# prepopulate the database with initial/default data
rails db:seed
</code></pre>
<h4>Rails 6</h4>
<p>Rails 6, adds
<a href="https://github.com/rails/rails/blob/98754de1412870d7dae9eba1c7bac944b9b90093/activerecord/lib/active_record/railties/databases.rake#L298">rails db:prepare</a>
to get rid of running all the above tasks individually. <code>rails db:prepare</code> first
calls the
<a href="https://github.com/rails/rails/blob/98754de1412870d7dae9eba1c7bac944b9b90093/activerecord/lib/active_record/railties/databases.rake#L306"><code>migrate</code></a>
to run the migrations, but if the database doesn't exist, <code>migrate</code> throws an
<code>ActiveRecord::NoDatabaseError</code>. Once it is
<a href="https://github.com/rails/rails/blob/98754de1412870d7dae9eba1c7bac944b9b90093/activerecord/lib/active_record/railties/databases.rake#L311">catched</a>,
it performs the following operations:</p>
<ul>
<li>Creates the database.</li>
<li>Loads the schema.</li>
<li>Seeds the database.</li>
</ul>
<p>Thus, <code>rails db:prepare</code> saves a lot of time spent on running database tasks
individually while setting up an application and finishes it with just one
command.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/35768">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds guard against DNS Rebinding attacks]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-guard-against-dns-rebinding-attacks"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-guard-against-dns-rebinding-attacks.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-guard-against-dns-rebinding-attacks</id>
      <published>2019-11-05T00:00:00.000Z</published>
      <updated>2019-11-05T00:00:00.000Z</updated>
      <author>
        <name>Midhun Krishna</name>
        <uri>https://www.bigbinary.com/blog/authors/midhunkrishna</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-guard-against-dns-rebinding-attacks.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds guard against DNS Rebinding attacks by whitelisting hosts via configuration]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-guard-against-dns-rebinding-attacks"><![CDATA[<p>In a DNS Rebinding attack, a malicious webpage runs client-side script when it
is loaded, to attack endpoints within a given network.</p>
<h3>What is DNS Rebinding attack?</h3>
<p>DNS Rebinding can be summarized as follows.</p>
<ul>
<li>An unsuspecting victim is tricked into loading <code>rebinding.network</code> which is
resolved by a DNS server controlled by a malicious entity.</li>
<li>Victims web browser sends a DNS query and gets the real IP address, say
<code>24.56.78.99</code> of <code>http://rebinding.network</code>. This DNS server also sets a very
short TTL value ( say 1 second ) on the response so that the client won't
cache this response for long.</li>
<li>The script on this webpage cannot attack services running in local network due
to CORS restrictions imposed by victims web browser. Instead it starts sending
a suspicious POST request to <code>http://rebinding.network/setup/reboot</code> with a
JSON payload <code>{params: factory-reset}</code>.</li>
<li>First few requests are indeed sent to <code>24.56.78.99</code> (real IP address), with
the DNS info from the cache, but then the browser sends out a DNS query for
<code>rebinding.network</code> when it observes that the cache has gone stale.</li>
<li>When the malicious DNS server gets the request for a second time, instead of
responding with <code>24.56.78.99</code> (which is the real IP address of
<code>rebinding.network</code>), it responds with <code>192.168.1.90</code>, an address at which, a
poorly secured smart device runs.</li>
</ul>
<p>Using this exploit, an attacker is able to factory-reset a device which relied
on security provided by local network.</p>
<p>This attack is explained in much more detail
<a href="https://medium.com/@brannondorsey/attacking-private-networks-from-the-internet-with-dns-rebinding-ea7098a2d325">in this blog post</a>.</p>
<h3>How does it affect Rails?</h3>
<p>Rails’s web console was particularly vulnerable to a Remote Code Execution (RCE)
via a DNS Rebinding.</p>
<p><a href="http://benmmurphy.github.io/blog/2016/07/11/rails-webconsole-dns-rebinding/">In this blog post</a>,
Ben Murphy goes into technical details of exploiting this vulnerability to open
Calculator app (only works in OS X).</p>
<h3>How does Rails 6 mitigate DNS Rebinding?</h3>
<p>Rails mitigates DNS Rebinding attack by maintaining a whitelist of domains from
which it can receive requests. This is achieved with a new
<a href="https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/host_authorization.rb">HostAuthorization</a>
middleware. This middleware leverages the fact that HOST request header is
<a href="https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name">a forbidden header</a>.</p>
<pre><code class="language-ruby"># taken from Rails documentation

# Allow requests from subdomains like `www.product.com` and
# `beta1.product.com`.
Rails.application.config.hosts &lt;&lt; &quot;.*\.product\.com/&quot;
</code></pre>
<p>In the above example, Rails would render a
<a href="https://github.com/rails/rails/blob/ee0d0b1220adda0ee48f67cc4340ff4d702f6ed9/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb">blocked host template</a>,
if it receives requests from domains outside of above whitelist.</p>
<p>In development environment, default whitelist includes <code>0.0.0.0/0, ::0</code>
(<a href="https://en.wikipedia.org/wiki/Default_route">CIDR notations for IPv4 and IPv6 default routes</a>)
and <code>localhost</code>. For all other environments, config.hosts is empty and host
header checks are not done.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActiveStorage::Blob#open]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-activestorage-blob-open"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activestorage-blob-open.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-activestorage-blob-open</id>
      <published>2019-10-30T00:00:00.000Z</published>
      <updated>2019-10-30T00:00:00.000Z</updated>
      <author>
        <name>Akhil Gautam</name>
        <uri>https://www.bigbinary.com/blog/authors/akhilgautam</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activestorage-blob-open.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds ActiveStorage::Blob#open which downloads a blob to a tempfile on disk and yields the tempfile. Processing a blob Let's take an example of a face detection application where the user...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-activestorage-blob-open"><![CDATA[<p>Rails 6 adds
<a href="https://edgeapi.rubyonrails.org/classes/ActiveStorage/Blob.html#method-i-open">ActiveStorage::Blob#open</a>
which downloads a blob to a tempfile on disk and yields the tempfile.</p>
<pre><code class="language-ruby">&gt;&gt; blob = ActiveStorage::Blob.first
=&gt; &lt;ActiveStorage::Blob id: 1, key: &quot;6qXeoibkvohP4VJiU4ytaEkH&quot;, filename: &quot;Screenshot 2019-08-26 at 10.24.40 AM.png&quot;, ..., created_at: &quot;2019-08-26 09:57:30&quot;&gt;

&gt;&gt; blob.open do |tempfile|
&gt;&gt;   puts tempfile.path  #do some processing
&gt;&gt; end
# Output: /var/folders/67/3n96myxs1rn5q_c47z7dthj80000gn/T/ActiveStorage-1-20190826-73742-mve41j.png
</code></pre>
<h3>Processing a blob</h3>
<p>Let's take an example of a face detection application where the user images are
uploaded. Let's assume that the images are uploaded on S3.</p>
<p>Before Rails 6, we will have to download the image in system's memory, process
it with an image processing program and then send the processed image back to
the S3 bucket.</p>
<h4>The overhead</h4>
<p>If the processing operation is successful, the original file can be deleted from
the system. We need to take care of a lot of uncertain events from the download
phase till the phase when the processed image is created.</p>
<h4>ActiveStorage::Blob#open to the rescue</h4>
<p>ActiveStorage::Blob#open, abstracts away all this complications and gives us a
tempfile which is closed and unlinked once the block is executed.</p>
<p> 1. <code>open</code> takes care of handling all the fanfare of getting a blob object
to a tempfile.  2. <code>open</code> takes care of the tempfile cleanup after the
block.</p>
<pre><code class="language-ruby">
&gt; &gt; blob = ActiveStorage::Blob.first
&gt; &gt; blob.open do |tempfile|
&gt; &gt; tempfile #do some processing
&gt; &gt; end

# once the given block is executed

# the tempfile is closed and unlinked

=&gt; #&lt;Tempfile: (closed)&gt;
</code></pre>
<p>By default, tempfiles are created in <code>Dir.tmpdir</code> directory, but
ActiveStorage::Blob#open also takes an optional argument <code>tmpdir</code> to set a
custom directory for storing the tempfiles.</p>
<pre><code class="language-ruby">
&gt; &gt; Dir.tmpdir
&gt; &gt; =&gt; &quot;/var/folders/67/3n96myxs1rn5q_c47z7dthj80000gn/T&quot;

&gt; &gt; blob = ActiveStorage::Blob.first
&gt; &gt; blob.open(tmpdir: &quot;/desired/path/to/save&quot;) do |tempfile|
&gt; &gt; puts tempfile.path #do some processing
&gt; &gt; end
&gt; &gt;
</code></pre>
<p>Here is the relevant
<a href="https://github.com/rails/rails/commit/9f95767979579f5761cb0d2bcccb67f3662349c5">commit</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActionMailer#email_address_with_name]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-actionmailer-email_address_with_name"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-actionmailer-email_address_with_name.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-actionmailer-email_address_with_name</id>
      <published>2019-10-22T00:00:00.000Z</published>
      <updated>2019-10-22T00:00:00.000Z</updated>
      <author>
        <name>Taha Husain</name>
        <uri>https://www.bigbinary.com/blog/authors/taha</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-actionmailer-email_address_with_name.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds email_address_with_name to ActionMailer to properly escape email addresses with names.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-actionmailer-email_address_with_name"><![CDATA[<p>When using <code>ActionMailer::Base#mail</code>, if we want to display name and email
address of the user in email, we can pass a string in format
<code>&quot;John Smith&quot; &lt;john@example.com&gt;</code> in <code>to</code>, <code>from</code> or <code>reply_to</code> options.</p>
<p>Before Rails 6, we had to join name and email address using string interpolation
as mentioned in
<a href="https://guides.rubyonrails.org/v5.2/action_mailer_basics.html#sending-email-with-name">Rails 5.2 Guides</a>
and shown below.</p>
<pre><code class="language-ruby">  email_with_name = %(&quot;John Smith&quot; &lt;john@example.com&gt;)
  mail(
    to: email_with_name,
    subject: 'Hey Rails 5.2!'
  )
</code></pre>
<p>Problem with string interpolation is it doesn't escape unexpected special
characters like quotes(&quot;) in the name.</p>
<p>Here's an example.</p>
<h3>Rails 5.2</h3>
<pre><code class="language-ruby">
irb(main):001:0&gt; %(&quot;John P Smith&quot; &lt;john@example.com&gt;)
=&gt; &quot;\&quot;John P Smith\&quot; &lt;john@example.com&gt;&quot;

irb(main):002:0&gt; %('John &quot;P&quot; Smith' &lt;john@example.com&gt;)
=&gt; &quot;'John \&quot;P\&quot; Smith' &lt;john@example.com&gt;&quot;

</code></pre>
<p>Rails 6 adds
<a href="https://github.com/rails/rails/pull/36454"><code>ActionMailer::Base#email_address_with_name</code></a>
to join name and email address in the format <code>&quot;John Smith&quot; &lt;john@example.com&gt;</code>
and take care of escaping special characters.</p>
<h3>Rails 6.1.0.alpha</h3>
<pre><code class="language-ruby">
irb(main):001:0&gt; ActionMailer::Base.email_address_with_name(&quot;john@example.com&quot;, &quot;John P Smith&quot;)
=&gt; &quot;John P Smith &lt;john@example.com&gt;&quot;

irb(main):002:0&gt; ActionMailer::Base.email_address_with_name(&quot;john@example.com&quot;, 'John &quot;P&quot; Smith')
=&gt; &quot;\&quot;John \\\&quot;P\\\&quot; Smith\&quot; &lt;john@example.com&gt;&quot;

</code></pre>
<pre><code class="language-ruby">mail(
to: email_address_with_name(&quot;john@example.com&quot;, &quot;John Smith&quot;),
subject: 'Hey Rails 6!'
)
</code></pre>
<p>Here's the relevant <a href="https://github.com/rails/rails/pull/36454">pull request</a>
for this change.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 raises ArgumentError if param contains colon]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-raises-argumenterror-if-custom-param-contains-a-colon"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-raises-argumenterror-if-custom-param-contains-a-colon.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-raises-argumenterror-if-custom-param-contains-a-colon</id>
      <published>2019-10-15T00:00:00.000Z</published>
      <updated>2019-10-15T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-raises-argumenterror-if-custom-param-contains-a-colon.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 raises ArgumentError if custom param contains a colon]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-raises-argumenterror-if-custom-param-contains-a-colon"><![CDATA[<p>The
<a href="https://guides.rubyonrails.org/routing.html#overriding-named-route-parameters">:param</a>
option in routes is used to override default resource identifier i.e. :id.</p>
<p>Let's take for an example that we want product :name to be as the default
resource identifier instead of :id while defining routes for <code>products</code>. In this
case,
<a href="https://guides.rubyonrails.org/routing.html#overriding-named-route-parameters">:param</a>
option comes handy. We will see below how we can use this option.</p>
<p>Before Rails 6, if
<a href="https://guides.rubyonrails.org/routing.html#overriding-named-route-parameters">resource custom param</a>
contains a colon, Rails used to consider that as an extra param which should not
be the case because it sneaks in an extra param.</p>
<p>An <a href="https://github.com/rails/rails/issues/30467">issue</a> was raised in Aug, 2017
which was later fixed in February this year.</p>
<p>So, now Rails 6 raises <code>ArgumentError</code> if a
<a href="https://guides.rubyonrails.org/routing.html#overriding-named-route-parameters">resource custom param</a>
contains a colon(:).</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<p>Let's create routes for <code>products</code> with custom param as <code>name/:pzn</code>.</p>
<pre><code class="language-ruby">
&gt; &gt; Rails.application.routes.draw do
&gt; &gt; resources :products, param: 'name/:pzn'
&gt; &gt; end
&gt; &gt;
</code></pre>
<pre><code class="language-plaintext">\$ rake routes | grep products
products GET /products(.:format) products#index
POST /products(.:format) products#create
new_product GET /products/new(.:format) products#new
edit_product GET /products/:name/:pzn/edit(.:format) products#edit
product GET /products/:name/:pzn(.:format) products#show
PATCH /products/:name/:pzn(.:format) products#update
PUT /products/:name/:pzn(.:format) products#update
DELETE /products/:name/:pzn(.:format) products#destroy
</code></pre>
<p>As we can see, Rails also considers <code>:pzn</code> as a parameter.</p>
<p>Now let's see how it works in Rails 6.</p>
<h4>Rails 6.0.0.rc1</h4>
<pre><code class="language-ruby">
&gt; &gt; Rails.application.routes.draw do
&gt; &gt; resources :products, param: 'name/:pzn'
&gt; &gt; end
&gt; &gt;
</code></pre>
<pre><code class="language-plaintext">\$ rake routes | grep products

rake aborted!
ArgumentError: :param option can't contain colons
/Users/amit/.rvm/gems/ruby-2.6.3/gems/actionpack-6.0.0.rc1/lib/action_dispatch/routing/mapper.rb:1149:in `initialize' /Users/amit/.rvm/gems/ruby-2.6.3/gems/actionpack-6.0.0.rc1/lib/action_dispatch/routing/mapper.rb:1472:in `new'
/Users/amit/.rvm/gems/ruby-2.6.3/gems/actionpack-6.0.0.rc1/lib/action_dispatch/routing/mapper.rb:1472:in `block in resources'
...
...
...
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/issues/30467">issue</a> and
the <a href="https://github.com/rails/rails/pull/35236">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 introduces new code loader called Zeitwerk]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-introduces-new-code-loader-called-zeitwerk"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-introduces-new-code-loader-called-zeitwerk.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-introduces-new-code-loader-called-zeitwerk</id>
      <published>2019-10-08T00:00:00.000Z</published>
      <updated>2019-10-08T00:00:00.000Z</updated>
      <author>
        <name>Midhun Krishna</name>
        <uri>https://www.bigbinary.com/blog/authors/midhunkrishna</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-introduces-new-code-loader-called-zeitwerk.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 introduces new code loader named Zeitwerk with better Ruby semantics and threadsafety]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-introduces-new-code-loader-called-zeitwerk"><![CDATA[<p><a href="https://github.com/fxn/zeitwerk">Zeitwerk</a> is the new code loader that
<a href="https://weblog.rubyonrails.org/2019/2/22/zeitwerk-integration-in-rails-6-beta-2#autoloading-modes">comes with Rails 6 by default</a>.
In addition to providing
<a href="https://guides.rubyonrails.org/autoloading_and_reloading_constants.html">autoloading, eager loading, and reloading capabilities</a>,
it also improves the classical code loader by being efficient and thread safe.
According to the author of Zeitwerk, <a href="https://twitter.com/fxn">Xavier Noria</a>,
one of the main motivations for writing Zeitwerk was to keep code DRY and to
remove the brittle <code>require</code> calls.</p>
<p>Zeitwerk is available as a gem with no additional dependencies. It means any
regular Ruby project can use Zeitwerk.</p>
<h3>How to use Zeitwerk</h3>
<p>Zeitwerk is baked in a Rails 6 project, thanks to the
<a href="https://github.com/rails/rails/blob/bfc9065d58508fb19dd1a4170406604dd3b3234a/activesupport/lib/active_support/dependencies/zeitwerk_integration.rb">Zeitwerk-Rails integration</a>.
For a non-Rails project, adding the following into the project's entry point
sets up Zeitwerk.</p>
<pre><code class="language-ruby">
loader = Zeitwerk::Loader.new
loader.push_dir(...)
loader.setup

</code></pre>
<p>For gem maintainers, Zeitwerk provides the handy <code>.for_gem</code> utility method</p>
<p>The following example from Zeitwerk documentation illustrates the usage of
<code>Zeitwerk.for_gem</code> method.</p>
<pre><code class="language-ruby">#lib/my_gem.rb (main file)

require &quot;zeitwerk&quot;
loader = Zeitwerk::Loader.for_gem
loader.setup

module MyGem
  # Since the setup has been performed, at this point we are already
  # able to reference project constants, in this case MyGem::MyLogger.
  include MyLogger
end

</code></pre>
<h3>How does Zeitwerk work?</h3>
<p>Before we look into Zeitwerk's internals, the following section provides a quick
refresher on constant-resolution in Ruby and how classical code loader of Rails
works.</p>
<p>Ruby's constant resolution looks for a constant in the following places.</p>
<ul>
<li>In each entry of Module.nesting</li>
<li>In each entry of Module.ancestors</li>
</ul>
<p>It triggers 'constant_missing' callback when it can't find the constant.</p>
<p>Ruby used to look for constants in Object.ancestors as well, but
<a href="https://github.com/ruby/ruby/commit/44a2576f798b07139adde2d279e48fdbe71a0148">that seems not the case anymore</a>.
An in-depth explanation of constant resolution can be found
<a href="https://cirw.in/blog/constant-lookup.html">at Conrad Irwin's blog</a>.</p>
<h5>Classical Code Loader in Rails</h5>
<p>Classical code loader (code loader in Rails version &lt; 6.0) achieves autoloading
by overriding
<a href="https://docs.ruby-lang.org/en/2.5.0/Module.html#method-i-const_missing">Module#const_missing</a>
and loads the missing constant without the need for an explicit require call as
long as the code follows certain conventions.</p>
<ul>
<li>The file should be within a directory in
ActiveSupport::Dependencies.autoload_paths</li>
<li>A file should be named after the class, i.e Admin::RoutesController =&gt;
admin/routes_controller.rb</li>
</ul>
<h5>Zeitwerk Mode</h5>
<p>Zeitwerk takes an entirely different approach in autoloading by registering
constants to be autoloaded by Ruby.</p>
<p>Consider the following configuration in which Zeitwerk manages <code>lib</code> directory
and <code>lib</code> has <code>automobile.rb</code> file.</p>
<pre><code class="language-ruby">
loader.push_dir('./lib')

</code></pre>
<p>Zeitwerk then uses
<a href="https://docs.ruby-lang.org/en/2.5.0/Module.html#method-i-autoload">Module.autoload</a>
to tell Ruby that &quot;Automobile&quot; can be found in &quot;lib/automobile.rb&quot;.</p>
<pre><code class="language-ruby">
autoload &quot;Automobile&quot;, &quot;lib/automobile.rb&quot;

</code></pre>
<p>Unlike classical loader, Zeitwerk takes module nesting into account while
loading constants by leveraging the new Tracepoint API to go look for constants
defined in subdirectories when a new class or module is defined.</p>
<p>Let us look at an example to understand this better.</p>
<pre><code class="language-ruby">
class Automobile
  # =&gt; Tracepoint hook triggers here.
  # include Engine
end

</code></pre>
<p>When
<a href="https://github.com/fxn/zeitwerk/blob/86064aba0c6e218c8bcc235b30c210a86c7c6ef8/lib/zeitwerk/explicit_namespace.rb#L78">the tracepoint hook</a>
triggers, Zeitwerk checks for an <code>automobile</code> directory in the same level as
automobile.rb and sets up Module.autoload for that directory and all the files
(in this case ./automobile/engine.rb) within that directory.</p>
<h3>Conclusion</h3>
<p>Previously in Rails, we had a code loader that was riddled with gotchas and
struggled to be thread safe. Zeitwerk does a better job by leveraging the new
Ruby standard API and matches Ruby's semantics for constants.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActiveSupport::ActionableError]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-active-support-actionable-error"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-active-support-actionable-error.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-active-support-actionable-error</id>
      <published>2019-10-01T00:00:00.000Z</published>
      <updated>2019-10-01T00:00:00.000Z</updated>
      <author>
        <name>Taha Husain</name>
        <uri>https://www.bigbinary.com/blog/authors/taha</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-active-support-actionable-error.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds support for dispatching actions from error page]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-active-support-actionable-error"><![CDATA[<p>When working in a team on a Rails application, we often bump into
<code>PendingMigrationError</code> or other errors that need us to run a rails command,
rake task etc.</p>
<p>Rails introduced a way to resolve such frequent errors in development from error
page itself.</p>
<p>Rails 6 added
<a href="https://github.com/rails/rails/pull/34788"><code>ActiveSupport::ActionableError</code></a>
module to define actions we want perform on errors, right from the error page.</p>
<p>For example, this is how <code>PendingMigrationError</code> page looks like in Rails 6.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-adds-active-support-actionable-error/rails-6.png" alt="How Actionable error looks like in Rails 6"></p>
<p>By default, a button is added on error screen that says <em>Run pending
migrations</em>. Clicking on this button would dispatch <code>rails db:migrate</code> action.
Page will reload once migrations run successfully.</p>
<p>We can also define custom actions to execute on errors.</p>
<h3>How to define actions on error?</h3>
<p>We need to include <code>ActiveSupport::ActionableError</code> module in our error class.
We can monkey patch an existing error class or define custom error class.</p>
<p><code>#action</code> api is provided to define actions on error. First argument in
<code>#action</code> is name of the action. This string would be displayed on the button on
error page. Second argument is a block where we can write commands or code to
fix the error.</p>
<p>Let's take an example of seeding posts data from controller, if posts not
already present.</p>
<pre><code class="language-ruby">
# app/controllers/posts_controller.rb

class PostsController &lt; ApplicationController

def index
@posts = Post.all
if @posts.empty?
raise PostsMissingError
end
end

end
</code></pre>
<pre><code class="language-ruby">
# app/errors/posts_missing_error.rb

class PostsMissingError &lt; StandardError

include ActiveSupport::ActionableError

action &quot;seed posts data&quot; do
Rails::Command.invoke 'posts:seed'
end

end

</code></pre>
<pre><code class="language-ruby">
# lib/tasks/posts.rake

namespace :posts do

desc 'posts seed task'
task :seed do
Post.create(title: 'First Post')
end

end
</code></pre>
<pre><code class="language-ruby">
# app/views/posts/index.html.erb

&lt;% @posts.each do |post| %&gt;
&lt;%= post.title %&gt;
&lt;% end %&gt;
</code></pre>
<p>Let's check <code>/posts</code> (<code>posts#index</code> action) when no posts are present. We would
get an error page with an action button on it as shown below.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-adds-active-support-actionable-error/posts-missing-error.png" alt="Actionable error - seed posts data"></p>
<p>Clicking on <em>seed posts data</em> action button will run our rake task and create
posts. Rails will automatically reload <code>/posts</code> after running rake task.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-adds-active-support-actionable-error/posts-index.png" alt="Posts index page"></p>
<p><a href="https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/actionable_exceptions.rb"><code>ActionDispatch::ActionableExceptions</code></a>
middleware takes care of invoking actions from error page.
<code>ActionableExceptions</code> middleware dispatches action to <code>ActionableError</code> and
redirects back when action block has successfully run. Action buttons are added
on error page from
<a href="https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb">this middleware template</a>.</p>
<p>Checkout the <a href="https://github.com/rails/rails/pull/34788">pull request</a> for more
information on actionable error.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 add_foreign_key & remove_foreign_key SQLite3]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3</id>
      <published>2019-09-24T00:00:00.000Z</published>
      <updated>2019-09-24T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds add_foreign_key and remove_foreign_key for SQLite3]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3"><![CDATA[<p>Rails provides
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key">add_foreign_key</a>
to add foreign key constraint for a column on a table.</p>
<p>It also provides
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key">remove_foreign_key</a>
to remove the foreign key constraint.</p>
<p>Before Rails 6,
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key">add_foreign_key</a>
and
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key">remove_foreign_key</a>
were not supported for SQLite3.</p>
<p>Rails 6 now adds this support. Now, we can create and remove foreign key
constraints using
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key">add_foreign_key</a>
and
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key">remove_foreign_key</a>
in SQLite3.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<p>We have two tables named as <code>orders</code> and <code>users</code>. Now, let's add foreign key
constraint of <code>users</code> in <code>orders</code> table using
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key">add_foreign_key</a>
and then try removing it using
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key">remove_foreign_key</a>.</p>
<pre><code class="language-ruby">&gt;&gt; class AddUserReferenceToOrders &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     add_column :orders, :user_id, :integer
&gt;&gt;     add_foreign_key :orders, :users
&gt;&gt;   end
&gt;&gt; end

=&gt; :change

&gt;&gt; AddUserReferenceToOrders.new.change
-- add_column(:orders, :user_id, :integer)
   (1.2ms)  ALTER TABLE &quot;orders&quot; ADD &quot;user_id&quot; integer
   -&gt; 0.0058s
-- add_foreign_key(:orders, :users)
   -&gt; 0.0000s

=&gt; nil

&gt;&gt; class RemoveUserForeignKeyFromOrders &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     remove_foreign_key :orders, :users
&gt;&gt;   end
&gt;&gt; end

=&gt; :change

&gt;&gt; RemoveUserForeignKeyFromOrders.new.change
-- remove_foreign_key(:orders, :users)
   -&gt; 0.0001s

=&gt; nil
</code></pre>
<p>We can see that
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key">add_foreign_key</a>
and
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key">remove_foreign_key</a>
are ignored by <code>Rails 5.2</code> with SQLite3.</p>
<h4>Rails 6.0.0.rc1</h4>
<p>We have two tables named as <code>orders</code> and <code>users</code>. Now, let's add foreign key
constraint of <code>users</code> in <code>orders</code> table using
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key">add_foreign_key</a>.</p>
<pre><code class="language-ruby">&gt;&gt; class AddUserReferenceToOrders &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     add_column :orders, :user_id, :integer
&gt;&gt;     add_foreign_key :orders, :users
&gt;&gt;   end
&gt;&gt; end

=&gt; :change

&gt;&gt; AddUserReferenceToOrders.new.change
-- add_column(:orders, :user_id, :integer)
   (1.0ms)  SELECT sqlite_version(*)
   (2.9ms)  ALTER TABLE &quot;orders&quot; ADD &quot;user_id&quot; integer
   -&gt; 0.0091s
-- add_foreign_key(:orders, :users)
   (0.0ms)  begin transaction
   (0.1ms)  PRAGMA foreign_keys
   (0.1ms)  PRAGMA defer_foreign_keys
   (0.0ms)  PRAGMA defer_foreign_keys = ON
   (0.1ms)  PRAGMA foreign_keys = OFF
   (0.2ms)  CREATE TEMPORARY TABLE &quot;aorders&quot; (&quot;id&quot; integer NOT NULL PRIMARY KEY, &quot;number&quot; varchar DEFAULT NULL, &quot;total&quot; decimal DEFAULT NULL, &quot;completed_at&quot; datetime DEFAULT NULL, &quot;created_at&quot; datetime(6) NOT NULL, &quot;updated_at&quot; datetime(6) NOT NULL, &quot;user_id&quot; integer DEFAULT NULL)
   (0.1ms)  INSERT INTO &quot;aorders&quot; (&quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot;)
                     SELECT &quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot; FROM &quot;orders&quot;
   (0.3ms)  DROP TABLE &quot;orders&quot;
   (0.1ms)  CREATE TABLE &quot;orders&quot; (&quot;id&quot; integer NOT NULL PRIMARY KEY, &quot;number&quot; varchar DEFAULT NULL, &quot;total&quot; decimal DEFAULT NULL, &quot;completed_at&quot; datetime DEFAULT NULL, &quot;created_at&quot; datetime(6) NOT NULL, &quot;updated_at&quot; datetime(6) NOT NULL, &quot;user_id&quot; integer DEFAULT NULL, CONSTRAINT &quot;fk_rails_f868b47f6a&quot;
FOREIGN KEY (&quot;user_id&quot;)
  REFERENCES &quot;users&quot; (&quot;id&quot;)
)
   (0.1ms)  INSERT INTO &quot;orders&quot; (&quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot;)
                     SELECT &quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot; FROM &quot;aorders&quot;
   (0.1ms)  DROP TABLE &quot;aorders&quot;
   (0.0ms)  PRAGMA defer_foreign_keys = 0
   (0.0ms)  PRAGMA foreign_keys = 1
   (0.6ms)  commit transaction
   -&gt; 0.0083s

=&gt; []

&gt;&gt; class RemoveUserForeignKeyFromOrders &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     remove_foreign_key :orders, :users
&gt;&gt;   end
&gt;&gt; end

=&gt; :change

&gt;&gt; RemoveUserForeignKeyFromOrders.new.change
-- remove_foreign_key(:orders, :users)
   (1.4ms)  SELECT sqlite_version(*)
   (0.0ms)  begin transaction
   (0.0ms)  PRAGMA foreign_keys
   (0.0ms)  PRAGMA defer_foreign_keys
   (0.0ms)  PRAGMA defer_foreign_keys = ON
   (0.0ms)  PRAGMA foreign_keys = OFF
   (0.2ms)  CREATE TEMPORARY TABLE &quot;aorders&quot; (&quot;id&quot; integer NOT NULL PRIMARY KEY, &quot;number&quot; varchar DEFAULT NULL, &quot;total&quot; decimal DEFAULT NULL, &quot;completed_at&quot; datetime DEFAULT NULL, &quot;created_at&quot; datetime(6) NOT NULL, &quot;updated_at&quot; datetime(6) NOT NULL, &quot;user_id&quot; integer DEFAULT NULL)
   (0.3ms)  INSERT INTO &quot;aorders&quot; (&quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot;)
                     SELECT &quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot; FROM &quot;orders&quot;
   (0.4ms)  DROP TABLE &quot;orders&quot;
   (0.1ms)  CREATE TABLE &quot;orders&quot; (&quot;id&quot; integer NOT NULL PRIMARY KEY, &quot;number&quot; varchar DEFAULT NULL, &quot;total&quot; decimal DEFAULT NULL, &quot;completed_at&quot; datetime DEFAULT NULL, &quot;created_at&quot; datetime(6) NOT NULL, &quot;updated_at&quot; datetime(6) NOT NULL, &quot;user_id&quot; integer DEFAULT NULL)
   (0.1ms)  INSERT INTO &quot;orders&quot; (&quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot;)
                     SELECT &quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot; FROM &quot;aorders&quot;
   (0.1ms)  DROP TABLE &quot;aorders&quot;
   (0.0ms)  PRAGMA defer_foreign_keys = 0
   (0.0ms)  PRAGMA foreign_keys = 1
   (0.7ms)  commit transaction
   -&gt; 0.0179s

=&gt; []
</code></pre>
<p>Now, let's remove foreign key constraint of <code>users</code> from <code>orders</code> table using
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key">remove_foreign_key</a>.</p>
<pre><code class="language-ruby">&gt;&gt; class RemoveUserForeignKeyFromOrders &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     remove_foreign_key :orders, :users
&gt;&gt;   end
&gt;&gt; end

=&gt; :change

&gt;&gt; RemoveUserForeignKeyFromOrders.new.change
-- remove_foreign_key(:orders, :users)
   (1.4ms)  SELECT sqlite_version(*)
   (0.0ms)  begin transaction
   (0.0ms)  PRAGMA foreign_keys
   (0.0ms)  PRAGMA defer_foreign_keys
   (0.0ms)  PRAGMA defer_foreign_keys = ON
   (0.0ms)  PRAGMA foreign_keys = OFF
   (0.2ms)  CREATE TEMPORARY TABLE &quot;aorders&quot; (&quot;id&quot; integer NOT NULL PRIMARY KEY, &quot;number&quot; varchar DEFAULT NULL, &quot;total&quot; decimal DEFAULT NULL, &quot;completed_at&quot; datetime DEFAULT NULL, &quot;created_at&quot; datetime(6) NOT NULL, &quot;updated_at&quot; datetime(6) NOT NULL, &quot;user_id&quot; integer DEFAULT NULL)
   (0.3ms)  INSERT INTO &quot;aorders&quot; (&quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot;)
                     SELECT &quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot; FROM &quot;orders&quot;
   (0.4ms)  DROP TABLE &quot;orders&quot;
   (0.1ms)  CREATE TABLE &quot;orders&quot; (&quot;id&quot; integer NOT NULL PRIMARY KEY, &quot;number&quot; varchar DEFAULT NULL, &quot;total&quot; decimal DEFAULT NULL, &quot;completed_at&quot; datetime DEFAULT NULL, &quot;created_at&quot; datetime(6) NOT NULL, &quot;updated_at&quot; datetime(6) NOT NULL, &quot;user_id&quot; integer DEFAULT NULL)
   (0.1ms)  INSERT INTO &quot;orders&quot; (&quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot;)
                     SELECT &quot;id&quot;,&quot;number&quot;,&quot;total&quot;,&quot;completed_at&quot;,&quot;created_at&quot;,&quot;updated_at&quot;,&quot;user_id&quot; FROM &quot;aorders&quot;
   (0.1ms)  DROP TABLE &quot;aorders&quot;
   (0.0ms)  PRAGMA defer_foreign_keys = 0
   (0.0ms)  PRAGMA foreign_keys = 1
   (0.7ms)  commit transaction
   -&gt; 0.0179s

=&gt; []
</code></pre>
<p>We can see here that with Rails 6,
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key">add_foreign_key</a>
and
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_foreign_key">remove_foreign_key</a>
work and were able to add and remove foreign key constraint respectively.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/35212">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActionDispatch::Request::Session#dig]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-actiondispatch-request-session-dig"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-actiondispatch-request-session-dig.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-actiondispatch-request-session-dig</id>
      <published>2019-09-18T00:00:00.000Z</published>
      <updated>2019-09-18T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-actiondispatch-request-session-dig.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 added ActionDispatch::Request::Session#dig. This works the same way as Hash#dig (Link is not available). It extracts the nested value specified by the sequence of keys. Hash#dig (Link is not...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-actiondispatch-request-session-dig"><![CDATA[<p>Rails 6 added
<a href="https://github.com/rails/rails/pull/32446">ActionDispatch::Request::Session#dig</a>.</p>
<p>This works the same way as Hash#dig (Link is not available).</p>
<p>It extracts the nested value specified by the sequence of keys.</p>
<p>Hash#dig (Link is not available) was introduced in <code>Ruby 2.3</code>.</p>
<p>Before Rails 6, we can achieve the same thing by first converting session to a
hash and then calling Hash#dig (Link is not available) on it.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<p>Let's add some user information in session and use dig after converting it to a
hash.</p>
<pre><code class="language-ruby">&gt;&gt; session[:user] = { email: 'jon@bigbinary.com', name: { first: 'Jon', last: 'Snow' }  }

=&gt; {:email=&gt;&quot;jon@bigbinary.com&quot;, :name=&gt;{:first=&gt;&quot;Jon&quot;, :last=&gt;&quot;Snow&quot;}}

&gt;&gt; session.to_hash

=&gt; {&quot;session_id&quot;=&gt;&quot;5fe8cc73c822361e53e2b161dcd20e47&quot;, &quot;_csrf_token&quot;=&gt;&quot;gyFd5nEEkFvWTnl6XeVbJ7qehgL923hJt8PyHVCH/DA=&quot;, &quot;return_to&quot;=&gt;&quot;http://localhost:3000&quot;, &quot;user&quot;=&gt;{:email=&gt;&quot;jon@bigbinary.com&quot;, :name=&gt;{:first=&gt;&quot;Jon&quot;, :last=&gt;&quot;Snow&quot;}}}


&gt;&gt; session.to_hash.dig(&quot;user&quot;, :name, :first)

=&gt; &quot;Jon&quot;
</code></pre>
<h4>Rails 6.0.0.rc1</h4>
<p>Let's add the same information to session and now use <code>dig</code> on session object
without converting it to a hash.</p>
<pre><code class="language-ruby">&gt;&gt; session[:user] = { email: 'jon@bigbinary.com', name: { first: 'Jon', last: 'Snow' }  }

=&gt; {:email=&gt;&quot;jon@bigbinary.com&quot;, :name=&gt;{:first=&gt;&quot;Jon&quot;, :last=&gt;&quot;Snow&quot;}}

&gt;&gt; session.dig(:user, :name, :first)

=&gt; &quot;Jon&quot;
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/32446">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Marking arrays of translations safe using html suffix]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix</id>
      <published>2019-09-11T00:00:00.000Z</published>
      <updated>2019-09-11T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 marks arrays of translations as trusted safe by using the _html suffix]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix"><![CDATA[<h3>Before Rails 6</h3>
<p>Before Rails 6, keys with the <code>_html</code> suffix in the language locale files are
automatically marked as HTML safe. These HTML safe keys do not get escaped when
used in the views.</p>
<pre><code class="language-yaml"># config/locales/en.yml

en:
  home:
    index:
      title_html: &lt;h2&gt;We build web &amp; mobile applications&lt;/h2&gt;
      description_html:
        We are a dynamic team of &lt;em&gt;developers&lt;/em&gt; and &lt;em&gt;designers&lt;/em&gt;.
      sections:
        blogs:
          title_html: &lt;h3&gt;Blogs &amp; publications&lt;/h3&gt;
          description_html:
            We regularly write our blog. Our blogs are covered by &lt;strong&gt;Ruby
            Inside&lt;/strong&gt; and &lt;strong&gt;Ruby Weekly Newsletter&lt;/strong&gt;.
</code></pre>
<pre><code class="language-erb">&lt;!-- app/views/home/index.html.erb --&gt;

&lt;%= t('.title_html') %&gt;
&lt;%= t('.description_html') %&gt;

&lt;%= t('.sections.blogs.title_html') %&gt;
&lt;%= t('.sections.blogs.description_html') %&gt;
</code></pre>
<p>Once rendered, this page looks like this.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix/before-rails-6-i18n-_html-suffix-without-array-key.png" alt="before-rails-6"></p>
<p>This way of marking translations as HTML safe by adding <code>_html</code> suffix to the
keys does not work as expected when the value is an array.</p>
<pre><code class="language-yaml">
# config/locales/en.yml

en:
home:
index:
title_html: &lt;h2&gt;We build web &amp; mobile applications&lt;/h2&gt;
description_html: We are a dynamic team of &lt;em&gt;developers&lt;/em&gt; and &lt;em&gt;designers&lt;/em&gt;.
sections:
blogs:
title_html: &lt;h3&gt;Blogs &amp; publications&lt;/h3&gt;
description_html: We regularly write our blog. Our blogs are covered by &lt;strong&gt;Ruby Inside&lt;/strong&gt; and &lt;strong&gt;Ruby Weekly Newsletter&lt;/strong&gt;.
services:
title_html: &lt;h3&gt;Services we offer&lt;/h3&gt;
list_html: - &lt;strong&gt;Ruby on Rails&lt;/strong&gt; - React.js &amp;#9883; - React Native &amp;#9883; &amp;#128241;
</code></pre>
<pre><code class="language-erb">
&lt;!-- app/views/home/index.html.erb --&gt;

&lt;%= t('.title_html') %&gt;
&lt;%= t('.description_html') %&gt;

&lt;%= t('.sections.blogs.title_html') %&gt;
&lt;%= t('.sections.blogs.description_html') %&gt;

&lt;%= t('.sections.services.title_html') %&gt;

&lt;ul&gt;
  &lt;% t('.sections.services.list_html').each do |service| %&gt;
    &lt;li&gt;&lt;%= service %&gt;&lt;/li&gt;
  &lt;% end %&gt;
&lt;ul&gt;
</code></pre>
<p>The rendered page escapes the unsafe HTML while rendering the array of
translations for the key <code>.sections.services.list_html</code> even though that key has
the <code>_html</code> suffix.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix/before-rails-6-i18n-_html-suffix-with-array-key.png" alt="before-rails-6"></p>
<p>A workaround is to manually mark all the translations in that array as HTML safe
using the methods such as <code>#raw</code> or <code>#html_safe</code>.</p>
<pre><code class="language-erb">
&lt;!-- app/views/home/index.html.erb --&gt;

&lt;%= t('.title_html') %&gt;
&lt;%= t('.description_html') %&gt;

&lt;%= t('.sections.blogs.title_html') %&gt;
&lt;%= t('.sections.blogs.description_html') %&gt;

&lt;%= t('.sections.services.title_html') %&gt;

&lt;ul&gt;
  &lt;% t('.sections.services.list_html').each do |service| %&gt;
    &lt;li&gt;&lt;%= service.html_safe %&gt;&lt;/li&gt;
  &lt;% end %&gt;
&lt;ul&gt;
</code></pre>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix/rails-6-i18n-array-key-with-_html-suffix.png" alt="rails-6-i18n"></p>
<h3>Arrays of translations are trusted as HTML safe by using the '_html' suffix in Rails 6</h3>
<p>In Rails 6, the unexpected behavior of not marking an array of translations as
HTML safe even though the key of that array has the <code>_html</code> suffix is fixed.</p>
<pre><code class="language-yaml"># config/locales/en.yml

en:
home:
index:
title_html: &lt;h2&gt;We build web &amp; mobile applications&lt;/h2&gt;
description_html: We are a dynamic team of &lt;em&gt;developers&lt;/em&gt; and &lt;em&gt;designers&lt;/em&gt;.
sections:
blogs:
title_html: &lt;h3&gt;Blogs &amp; publications&lt;/h3&gt;
description_html: We regularly write our blog. Our blogs are covered by &lt;strong&gt;Ruby Inside&lt;/strong&gt; and &lt;strong&gt;Ruby Weekly Newsletter&lt;/strong&gt;.
services:
title_html: &lt;h3&gt;Services we offer&lt;/h3&gt;
list_html: - &lt;strong&gt;Ruby on Rails&lt;/strong&gt; - React.js &amp;#9883; - React Native &amp;#9883; &amp;#128241;
</code></pre>
<pre><code class="language-erb">
&lt;!-- app/views/home/index.html.erb --&gt;

&lt;%= t('.title_html') %&gt;
&lt;%= t('.description_html') %&gt;

&lt;%= t('.sections.blogs.title_html') %&gt;
&lt;%= t('.sections.blogs.description_html') %&gt;

&lt;%= t('.sections.services.title_html') %&gt;

&lt;ul&gt;
  &lt;% t('.sections.services.list_html').each do |service| %&gt;
    &lt;li&gt;&lt;%= service %&gt;&lt;/li&gt;
  &lt;% end %&gt;
&lt;ul&gt;
</code></pre>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-marks-arrays-of-translations-as-trusted-safe-by-using-the-_html-suffix/rails-6-i18n-array-key-with-_html-suffix.png" alt="rails-6-i18n"></p>
<p>We can see above that we no longer need to manually mark the translations as
HTML safe for the key <code>.sections.services.title_html</code> using the methods such as
<code>#raw</code> or <code>#html_safe</code> since that key has the <code>_html</code> suffix.</p>
<hr>
<p>To learn more about this feature, please checkout
<a href="https://github.com/rails/rails/pull/32361">rails/rails#32361</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds filter_attributes on ActiveRecord::Base]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-activerecord-base-filter_attributes"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activerecord-base-filter_attributes.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-activerecord-base-filter_attributes</id>
      <published>2019-09-03T00:00:00.000Z</published>
      <updated>2019-09-03T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activerecord-base-filter_attributes.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[A lot of times, we ask user for sensitive data such as password, credit card number etc. We should not be able to see this information in logs. So, there must be a way in Rails to filter out these...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-activerecord-base-filter_attributes"><![CDATA[<p>A lot of times, we ask user for sensitive data such as password, credit card
number etc. We should not be able to see this information in logs. So, there
must be a way in Rails to filter out these parameters from logs.</p>
<p>Rails provides a way of doing this. We can add parameters to
<a href="https://guides.rubyonrails.org/configuring.html#initializers">Rails.application.config.filter_parameters</a>.</p>
<p>There is one more way of doing this in Rails. We can also use
<a href="https://api.rubyonrails.org/classes/ActionDispatch/Http/FilterParameters.html">https://api.rubyonrails.org/classes/ActionDispatch/Http/FilterParameters.html</a>.</p>
<p>However there is still a security issue when we call inspect on an ActiveRecord
object for logging purposes. In this case, Rails does not consider
<a href="https://guides.rubyonrails.org/configuring.html#initializers">Rails.application.config.filter_parameters</a>
and displays the sensitive information.</p>
<p>Rails 6 fixes this. It considers
<a href="https://guides.rubyonrails.org/configuring.html#initializers">Rails.application.config.filter_parameters</a>
while inspecting an object.</p>
<p>Rails 6 also provides an alternative way to filter columns on ActiveRecord level
by adding <a href="https://github.com/rails/rails/pull/33756">filter_attributes</a> on
ActiveRecord::Base.</p>
<p>In Rails 6, <a href="https://github.com/rails/rails/pull/33756">filter_attributes</a> on
ActiveRecord::Base takes priority over
<a href="https://guides.rubyonrails.org/configuring.html#initializers">Rails.application.config.filter_parameters</a>.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 6.0.0.rc1</h4>
<p>Let's create a user record and call inspect on it.</p>
<pre><code class="language-ruby">&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;  validates :email, :password, presence: true
&gt;&gt; end

=&gt; {:presence=&gt;true}

&gt;&gt; User.create(email: 'john@bigbinary.com', password: 'john_wick_bigbinary')
BEGIN
  User Create (0.6ms)  INSERT INTO &quot;users&quot; (&quot;email&quot;, &quot;password&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES ($1, $2, $3, $4) RETURNING &quot;id&quot;  [[&quot;email&quot;, &quot;john@bigbinary.com&quot;], [&quot;password&quot;, &quot;john_wick_bigbinary&quot;], [&quot;created_at&quot;, &quot;2019-05-17 21:34:34.504394&quot;], [&quot;updated_at&quot;, &quot;2019-05-17 21:34:34.504394&quot;]]
COMMIT

=&gt; #&lt;User id: 2, email: &quot;john@bigbinary.com&quot;, password: [FILTERED], created_at: &quot;2019-05-17 21:34:34&quot;, updated_at: &quot;2019-05-17 21:34:34&quot;&gt;
</code></pre>
<p>We can see that <code>password</code> is filtered as it is added to
<a href="https://guides.rubyonrails.org/configuring.html#initializers">Rails.application.config.filter_parameters</a>
by default in <code>config/initializers/filter_parameter_logging.rb</code>.</p>
<p>Now let's add just <code>:email</code> to <code>User.filter_attributes</code></p>
<pre><code class="language-ruby">&gt;&gt; User.filter_attributes = [:email]

=&gt; [:email]

&gt;&gt; User.first.inspect
SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;id&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; &quot;#&lt;User id: 2, email: [FILTERED], password: \&quot;john_wick_bigbinary\&quot;, created_at: \&quot;2019-05-17 21:34:34\&quot;, updated_at: \&quot;2019-05-17 21:34:34\&quot;&gt;&quot;
</code></pre>
<p>We can see here that <code>User.filter_attributes</code> took priority over
<a href="https://guides.rubyonrails.org/configuring.html#initializers">Rails.application.config.filter_parameters</a>
and removed filtering from password and filtered just email.</p>
<p>Now, let's add both <code>:email</code> and <code>:password</code> to <code>User.filter_attributes</code>.</p>
<pre><code class="language-ruby">&gt;&gt; User.filter_attributes = [:email, :password]

=&gt; [:email, :password]

&gt;&gt; User.first.inspect

=&gt; &quot;#&lt;User id: 2, email: [FILTERED], password: [FILTERED], created_at: \&quot;2019-05-17 21:34:34\&quot;, updated_at: \&quot;2019-05-17 21:34:34\&quot;&gt;&quot;
</code></pre>
<p>We can see that now both <code>email</code> and <code>password</code> are filtered out.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/33756">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[ArgumentError for invalid :limit & :precision Rails 6]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-raises-argumenterror-for-invalid-limit-and-precision"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-raises-argumenterror-for-invalid-limit-and-precision.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-raises-argumenterror-for-invalid-limit-and-precision</id>
      <published>2019-08-27T00:00:00.000Z</published>
      <updated>2019-08-27T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-raises-argumenterror-for-invalid-limit-and-precision.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 raises ArgumentError for invalid :limit and :precision]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-raises-argumenterror-for-invalid-limit-and-precision"><![CDATA[<p>Rails 6 raises <a href="https://apidock.com/ruby/ArgumentError">ArgumentError</a> when
<code>:limit</code> and <code>:precision</code> are used with invalid datatypes.</p>
<p>Before Rails 6, it used to return
<a href="https://api.rubyonrails.org/classes/ActiveRecord/ActiveRecordError.html">ActiveRecord::ActiveRecordError</a>.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<p>Let's create an orders table and try using <code>:limit</code> with a column named as
quantity with data type <code>integer</code>.</p>
<pre><code class="language-ruby">
&gt; &gt; class CreateOrders &lt; ActiveRecord::Migration[5.2]
&gt; &gt; def change
&gt; &gt; create_table :orders do |t|
&gt; &gt; t.string :item
&gt; &gt; t.integer :quantity, limit: 10
&gt; &gt;
&gt; &gt;       t.timestamps
&gt; &gt;     end
&gt; &gt;
&gt; &gt; end
&gt; &gt; end

=&gt; :change

&gt; &gt; CreateOrders.new.change
&gt; &gt; -- create_table(:orders)

=&gt; Traceback (most recent call last):
2: from (irb):11
1: from (irb):3:in 'change'
ActiveRecord::ActiveRecordError (No integer type has byte size 10. Use a numeric with scale 0 instead.)
</code></pre>
<p>We can see that use of <code>:limit</code> with <code>integer</code> column raises
<a href="https://api.rubyonrails.org/classes/ActiveRecord/ActiveRecordError.html">ActiveRecord::ActiveRecordError</a>
in <code>Rails 5.2</code>.</p>
<p>Now let's try using <code>:precision</code> of <code>10</code> with a <code>datetime</code> column.</p>
<pre><code class="language-ruby">
&gt; &gt; class CreateOrders &lt; ActiveRecord::Migration[5.2]
&gt; &gt; def change
&gt; &gt; create_table :orders do |t|
&gt; &gt; t.string :item
&gt; &gt; t.integer :quantity
&gt; &gt; t.datetime :completed_at, precision: 10
&gt; &gt;
&gt; &gt;       t.timestamps
&gt; &gt;     end
&gt; &gt;
&gt; &gt; end
&gt; &gt; end

=&gt; :change

&gt; &gt; CreateOrders.new.change
&gt; &gt; -- create_table(:orders)

=&gt; Traceback (most recent call last):
2: from (irb):12
1: from (irb):3:in 'change'
ActiveRecord::ActiveRecordError (No timestamp type has precision of 10. The allowed range of precision is from 0 to 6)
</code></pre>
<p>We can see that invalid value of <code>:precision</code> with datetime column also raises
<a href="https://api.rubyonrails.org/classes/ActiveRecord/ActiveRecordError.html">ActiveRecord::ActiveRecordError</a>
in <code>Rails 5.2</code>.</p>
<h4>Rails 6.0.0.rc1</h4>
<p>Let's create an orders table and try using <code>:limit</code> with a column named as
quantity with data type <code>integer</code> in Rails 6.</p>
<pre><code class="language-ruby">
&gt; &gt; class CreateOrders &lt; ActiveRecord::Migration[6.0]
&gt; &gt; def change
&gt; &gt; create_table :orders do |t|
&gt; &gt; t.string :item
&gt; &gt; t.integer :quantity, limit: 10
&gt; &gt;
&gt; &gt;       t.timestamps
&gt; &gt;     end
&gt; &gt;
&gt; &gt; end
&gt; &gt; end

=&gt; :change

&gt; &gt; CreateOrders.new.change
&gt; &gt; -- create_table(:orders)

=&gt; Traceback (most recent call last):
2: from (irb):11
1: from (irb):3:in 'change'
ArgumentError (No integer type has byte size 10. Use a numeric with scale 0 instead.)
</code></pre>
<p>We can see that use of <code>:limit</code> with <code>integer</code> column raises
<a href="https://apidock.com/ruby/ArgumentError">ArgumentError</a> in <code>Rails 6</code>.</p>
<p>Now let's try using <code>:precision</code> of <code>10</code> with a <code>datetime</code> column.</p>
<pre><code class="language-ruby">
&gt; &gt; class CreateOrders &lt; ActiveRecord::Migration[6.0]
&gt; &gt; def change
&gt; &gt; create_table :orders do |t|
&gt; &gt; t.string :item
&gt; &gt; t.integer :quantity
&gt; &gt; t.datetime :completed_at, precision: 10
&gt; &gt;
&gt; &gt;       t.timestamps
&gt; &gt;     end
&gt; &gt;
&gt; &gt; end
&gt; &gt; end

=&gt; :change

&gt; &gt; CreateOrders.new.change
&gt; &gt; -- create_table(:orders)

=&gt; Traceback (most recent call last):
2: from (irb):12
1: from (irb):3:in 'change'
ArgumentError (No timestamp type has precision of 10. The allowed range of precision is from 0 to 6)
</code></pre>
<p>We can see that invalid value of <code>:precision</code> with datetime column also raises
<a href="https://apidock.com/ruby/ArgumentError">ArgumentError</a> in <code>Rails 6</code>.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/35887">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 Pass custom config to ActionCable::Server::Base]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-allows-passing-custom-configuration-to-actioncable-server-base"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-allows-passing-custom-configuration-to-actioncable-server-base.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-allows-passing-custom-configuration-to-actioncable-server-base</id>
      <published>2019-08-21T00:00:00.000Z</published>
      <updated>2019-08-21T00:00:00.000Z</updated>
      <author>
        <name>Taha Husain</name>
        <uri>https://www.bigbinary.com/blog/authors/taha</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-allows-passing-custom-configuration-to-actioncable-server-base.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 allows passing custom configuration to ActionCable::Server::Base]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-allows-passing-custom-configuration-to-actioncable-server-base"><![CDATA[<p>Before Rails 6, Action Cable server used default configuration on boot up,
unless custom configuration is provided explicitly.</p>
<p>Custom configuration can be mentioned in either <code>config/cable.yml</code> or
<code>config/application.rb</code> as shown below.</p>
<pre><code class="language-ruby"># config/cable.yml

production:
  url: redis://redis.example.com:6379
  adapter: redis
  channel_prefix: custom_

</code></pre>
<p>Or</p>
<pre><code class="language-ruby"># config/application.rb

config.action_cable.cable = { adapter: &quot;redis&quot;, channel_prefix: &quot;custom_&quot; }

</code></pre>
<p>In some cases, we need another Action Cable server running separately from
application with a different set of configuration.</p>
<p>Problem is that both approaches mentioned earlier set Action Cable server
configuration on application boot up. This configuration can not be changed for
the second server.</p>
<p>Rails 6 has added a provision to pass custom configuration. Rails 6 allows us to
pass <code>ActionCable::Server::Configuration</code> object as an option when initializing
a new Action Cable server.</p>
<pre><code class="language-ruby">
config = ActionCable::Server::Configuration.new
config.cable = { adapter: &quot;redis&quot;, channel_prefix: &quot;custom_&quot; }

ActionCable::Server::Base.new(config: config)

</code></pre>
<p>For more details on Action Cable configurations, head to
<a href="https://edgeguides.rubyonrails.org/action_cable_overview.html#configuration">Action Cable docs</a>.</p>
<p>Here's the relevant <a href="https://github.com/rails/rails/pull/34714">pull request</a>
for this change.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds support of symbol keys]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-activesupport-hashwithindifferentaccess-assoc"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activesupport-hashwithindifferentaccess-assoc.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-activesupport-hashwithindifferentaccess-assoc</id>
      <published>2019-08-20T00:00:00.000Z</published>
      <updated>2019-08-20T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activesupport-hashwithindifferentaccess-assoc.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds support of symbol keys with ActiveSupport::HashWithIndifferentAccess#assoc]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-activesupport-hashwithindifferentaccess-assoc"><![CDATA[<p>Rails 6 added support of symbol keys with
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/HashWithIndifferentAccess.html#method-i-assoc">ActiveSupport::HashWithIndifferentAccess#assoc</a>.</p>
<p>Please note that documentation of
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/HashWithIndifferentAccess.html#method-i-assoc">ActiveSupport::HashWithIndifferentAccess#assoc</a>
in Rails 5.2 shows that
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/HashWithIndifferentAccess.html#method-i-assoc">ActiveSupport::HashWithIndifferentAccess#assoc</a>
works with symbol keys but it doesn't.</p>
<p>In Rails 6,
<a href="https://github.com/rails/rails/pull/35080">ActiveSupport::HashWithIndifferentAccess</a>
implements a hash where string and symbol keys are considered to be the same.</p>
<p>Before Rails 6, <code>HashWithIndifferentAccess#assoc</code> used to work with just string
keys.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<p>Let's create an object of
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/HashWithIndifferentAccess.html">ActiveSupport::HashWithIndifferentAccess</a>
and call <code>assoc</code> on that object.</p>
<pre><code class="language-ruby">&gt;&gt; info = { name: 'Mark', email: 'mark@bigbinary.com' }.with_indifferent_access

=&gt; {&quot;name&quot;=&gt;&quot;Mark&quot;, &quot;email&quot;=&gt;&quot;mark@bigbinary.com&quot;}

&gt;&gt; info.assoc(:name)

=&gt; nil

&gt;&gt; info.assoc('name')

=&gt; [&quot;name&quot;, &quot;Mark&quot;]
</code></pre>
<p>We can see that <code>assoc</code> does not work with symbol keys with
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/HashWithIndifferentAccess.html">ActiveSupport::HashWithIndifferentAccess</a>
in Rails 5.2.</p>
<h4>Rails 6.0.0.beta2</h4>
<p>Now, let's call <code>assoc</code> on the same hash in Rails 6 with both string and symbol
keys.</p>
<pre><code class="language-ruby">&gt;&gt; info = { name: 'Mark', email: 'mark@bigbinary.com' }.with_indifferent_access

=&gt; {&quot;name&quot;=&gt;&quot;Mark&quot;, &quot;email&quot;=&gt;&quot;mark@bigbinary.com&quot;}

&gt;&gt; info.assoc(:name)

=&gt; [&quot;name&quot;, &quot;Mark&quot;]

&gt;&gt; info.assoc('name')

=&gt; [&quot;name&quot;, &quot;Mark&quot;]
</code></pre>
<p>As we can see, <code>assoc</code> works perfectly fine with both string and symbol keys
with
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/HashWithIndifferentAccess.html">ActiveSupport::HashWithIndifferentAccess</a>
in Rails 6.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/35080">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 preserves status of #html_safe?]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-preserves-status-of-html_safe-on-sliced-and-multiplied-html-safe-strings"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-preserves-status-of-html_safe-on-sliced-and-multiplied-html-safe-strings.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-preserves-status-of-html_safe-on-sliced-and-multiplied-html-safe-strings</id>
      <published>2019-08-13T00:00:00.000Z</published>
      <updated>2019-08-13T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-preserves-status-of-html_safe-on-sliced-and-multiplied-html-safe-strings.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 preserves status of #html_safe? on HTML safe strings which are sliced or multiplied using `ActiveSupport::SafeBuffer#*`]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-preserves-status-of-html_safe-on-sliced-and-multiplied-html-safe-strings"><![CDATA[<h2>Before Rails 6</h2>
<p>Before Rails 6, calling <code>#html_safe?</code> on a slice of an HTML safe string returns
<code>nil</code>.</p>
<pre><code class="language-ruby">&gt;&gt; html_content = &quot;&lt;div&gt;Hello, world!&lt;/div&gt;&quot;.html_safe
# =&gt; &quot;&lt;div&gt;Hello, world!&lt;/div&gt;&quot;
&gt;&gt; html_content.html_safe?
# =&gt; true
&gt;&gt; html_content[0..-1].html_safe?
# =&gt; nil
</code></pre>
<p>Also, before Rails 6, the <code>ActiveSupport::SafeBuffer#*</code> method does not preserve
the HTML safe status as well.</p>
<pre><code class="language-ruby">&gt;&gt; line_break = &quot;&lt;br /&gt;&quot;.html_safe
# =&gt; &quot;&lt;br /&gt;&quot;
&gt;&gt; line_break.html_safe?
# =&gt; true
&gt;&gt; two_line_breaks = (line_break * 2)
# =&gt; &quot;&lt;br /&gt;&lt;br /&gt;&quot;
&gt;&gt; two_line_breaks.html_safe?
# =&gt; nil
</code></pre>
<h2>Rails 6 returns expected status of <code>#html_safe?</code></h2>
<p>In Rails 6, both of the above cases have been fixed properly.</p>
<p>Therefore, we will now get the status of <code>#html_safe?</code> as expected.</p>
<pre><code class="language-ruby">&gt;&gt; html_content = &quot;&lt;div&gt;Hello, world!&lt;/div&gt;&quot;.html_safe
# =&gt; &quot;&lt;div&gt;Hello, world!&lt;/div&gt;&quot;
&gt;&gt; html_content.html_safe?
# =&gt; true
&gt;&gt; html_content[0..-1].html_safe?
# =&gt; true

&gt;&gt; line_break = &quot;&lt;br /&gt;&quot;.html_safe
# =&gt; &quot;&lt;br /&gt;&quot;
&gt;&gt; line_break.html_safe?
# =&gt; true
&gt;&gt; two_line_breaks = (line_break * 2)
# =&gt; &quot;&lt;br /&gt;&lt;br /&gt;&quot;
&gt;&gt; two_line_breaks.html_safe?
# =&gt; true
</code></pre>
<p>Please check <a href="https://github.com/rails/rails/pull/33808">rails/rails#33808</a> and
<a href="https://github.com/rails/rails/pull/36012">rails/rails#36012</a> for the relevant
changes.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Recyclable cache keys in Rails]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-adds-support-for-recyclable-cache-keys"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-adds-support-for-recyclable-cache-keys.png"/>
      <id>https://www.bigbinary.com/blog/rails-adds-support-for-recyclable-cache-keys</id>
      <published>2019-08-06T00:00:00.000Z</published>
      <updated>2019-08-06T00:00:00.000Z</updated>
      <author>
        <name>Taha Husain</name>
        <uri>https://www.bigbinary.com/blog/authors/taha</uri>
      </author>
      <category term="Rails 5.2"/>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-adds-support-for-recyclable-cache-keys.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails added cache_versioning and collection_cache_versioning to support recyclable cache keys.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-adds-support-for-recyclable-cache-keys"><![CDATA[<p><a href="https://github.com/rails/rails/pull/29092">Recyclable cache keys</a> or <em>cache
versioning</em> was introduced in Rails 5.2. Large applications frequently need to
invalidate their cache because cache store has limited memory. We can optimize
cache storage and minimize cache miss using recyclable cache keys.</p>
<p>Recyclable cache keys is supported by all
<a href="https://guides.rubyonrails.org/caching_with_rails.html#cache-stores">cache stores</a>
that ship with Rails.</p>
<p>Before Rails 5.2, <code>cache_key</code>'s format was <em>{model_name}/{id}-{update_at}</em>. Here
<code>model_name</code> and <code>id</code> are always constant for an object and <code>updated_at</code> changes
on every update.</p>
<h4>Rails 5.1</h4>
<pre><code class="language-ruby">&gt;&gt; post = Post.last

&gt;&gt; post.cache_key
=&gt; &quot;posts/1-20190522104553296111&quot;

# Update post
&gt;&gt; post.touch

&gt;&gt; post.cache_key
=&gt; &quot;posts/1-20190525102103422069&quot; # cache_key changed

</code></pre>
<p>In Rails 5.2, <code>#cache_key</code> returns <em>{model_name}/{id}</em> and new method
<code>#cache_version</code> returns <em>{updated_at}</em>.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">
&gt;&gt; ActiveRecord::Base.cache_versioning = true

&gt;&gt; post = Post.last

&gt;&gt; post.cache_key
=&gt; &quot;posts/1&quot;

&gt;&gt; post.cache_version
=&gt; &quot;20190522070715422750&quot;

&gt;&gt; post.cache_key_with_version
=&gt; &quot;posts/1-20190522070715422750&quot;

</code></pre>
<p>Let's update <code>post</code> instance and check <code>cache_key</code> and <code>cache_version</code>'s
behaviour.</p>
<pre><code class="language-ruby">
&gt;&gt; post.touch

&gt;&gt; post.cache_key
=&gt; &quot;posts/1&quot; # cache_key remains same

&gt;&gt; post.cache_version
=&gt; &quot;20190527062249879829&quot; # cache_version changed

</code></pre>
<p>To use cache versioning feature, we have to enable
<code>ActiveRecord::Base.cache_versioning</code> configuration. By default
<code>cache_versioning</code> config is set to false for backward compatibility.</p>
<p>We can enable cache versioning configuration globally as shown below.</p>
<pre><code class="language-ruby">
ActiveRecord::Base.cache_versioning = true
# or
config.active_record.cache_versioning = true

</code></pre>
<p>Cache versioning config can be applied at model level.</p>
<pre><code class="language-ruby">
class Post &lt; ActiveRecord::Base
  self.cache_versioning = true
end

# Or, when setting `#cache_versioning` outside the model -

Post.cache_versioning = true

</code></pre>
<p>Let's understand the problem step by step with cache keys before Rails 5.2.</p>
<h4>Rails 5.1 (without cache versioning)</h4>
<p><em>1. Write <code>post</code> instance to cache using
<a href="https://apidock.com/rails/ActiveSupport/Cache/Store/fetch"><code>fetch</code></a> api.</em></p>
<pre><code class="language-ruby">
&gt;&gt; before_update_cache_key = post.cache_key
=&gt; &quot;posts/1-20190527062249879829&quot;

&gt;&gt; Rails.cache.fetch(before_update_cache_key) { post }
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 06:22:49&quot;&gt;

</code></pre>
<p><em>2. Update <code>post</code> instance using
<a href="https://apidock.com/rails/ActiveRecord/Persistence/touch"><code>touch</code></a>.</em></p>
<pre><code class="language-ruby">
&gt;&gt; post.touch
   (0.1ms)  begin transaction
  Post Update (1.6ms)  UPDATE &quot;posts&quot; SET &quot;updated_at&quot; = ? WHERE &quot;posts&quot;.&quot;id&quot; = ?  [[&quot;updated_at&quot;, &quot;2019-05-27 08:01:52.975653&quot;], [&quot;id&quot;, 1]]
   (1.2ms)  commit transaction
=&gt; true

</code></pre>
<p><em>3. Verify stale <code>cache_key</code> in cache store.</em></p>
<pre><code class="language-ruby">
&gt;&gt; Rails.cache.fetch(before_update_cache_key)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 06:22:49&quot;&gt;

</code></pre>
<p><em>4. Write updated <code>post</code> instance to cache using new <code>cache_key</code>.</em></p>
<pre><code class="language-ruby">&gt;&gt; after_update_cache_key = post.cache_key
=&gt; &quot;posts/1-20190527080152975653&quot;

&gt;&gt; Rails.cache.fetch(after_update_cache_key) { post }
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 08:01:52&quot;&gt;

</code></pre>
<p><em>5. Cache store now has two copies of <code>post</code> instance.</em></p>
<pre><code class="language-ruby">
&gt;&gt; Rails.cache.fetch(before_update_cache_key)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 06:22:49&quot;&gt;

&gt;&gt; Rails.cache.fetch(after_update_cache_key)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 08:01:52&quot;&gt;

</code></pre>
<p><em>cache_key</em> and its associated instance becomes irrelevant as soon as an
instance is updated. But it stays in cache store until it is manually
invalidated.</p>
<p>This sometimes result in overflowing cache store with stale keys and data. In
applications that extensively use cache store, a huge chunk of cache store gets
filled with stale data frequently.</p>
<p>Now let's take a look at the same example. This time with <em>cache versioning</em> to
understand how recyclable cache keys help optimize cache storage.</p>
<h4>Rails 5.2 (cache versioning)</h4>
<p><em>1. Write <code>post</code> instance to cache store with <code>version</code> option.</em></p>
<pre><code class="language-ruby">
&gt;&gt; ActiveRecord::Base.cache_versioning = true

&gt;&gt; post = Post.last

&gt;&gt; cache_key = post.cache_key
=&gt; &quot;posts/1&quot;

&gt;&gt; before_update_cache_version = post.cache_version
=&gt; &quot;20190527080152975653&quot;

&gt;&gt; Rails.cache.fetch(cache_key, version: before_update_cache_version) { post }
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 08:01:52&quot;&gt;

</code></pre>
<p><em>2. Update <code>post</code> instance.</em></p>
<pre><code class="language-ruby">
&gt;&gt; post.touch
   (0.1ms)  begin transaction
  Post Update (0.4ms)  UPDATE &quot;posts&quot; SET &quot;updated_at&quot; = ? WHERE &quot;posts&quot;.&quot;id&quot; = ?  [[&quot;updated_at&quot;, &quot;2019-05-27 09:09:15.651029&quot;], [&quot;id&quot;, 1]]
   (0.7ms)  commit transaction
=&gt; true

</code></pre>
<p><em>3. Verify stale <code>cache_version</code> in cache store.</em></p>
<pre><code class="language-ruby">
&gt;&gt; Rails.cache.fetch(cache_key, version: before_update_cache_version)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 08:01:52&quot;&gt;

</code></pre>
<p><em>4. Write updated <code>post</code> instance to cache.</em></p>
<pre><code class="language-ruby">
&gt;&gt; after_update_cache_version = post.cache_version
=&gt; &quot;20190527090915651029&quot;

&gt;&gt; Rails.cache.fetch(cache_key, version: after_update_cache_version) { post }
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 09:09:15&quot;&gt;

</code></pre>
<p><em>5. Cache store has replaced old copy of <code>post</code> with new version automatically.</em></p>
<pre><code class="language-ruby">
&gt;&gt; Rails.cache.fetch(cache_key, version: before_update_cache_version)
=&gt; nil

&gt;&gt; Rails.cache.fetch(cache_key, version: after_update_cache_version)
=&gt; #&lt;Post id: 1, title: &quot;First Post&quot;, created_at: &quot;2019-05-22 17:23:22&quot;, updated_at: &quot;2019-05-27 09:09:15&quot;&gt;

</code></pre>
<p>Above example shows how recyclable cache keys maintains single, latest copy of
an instance. Stale versions are removed automatically when new version is added
to cache store.</p>
<p><em>Rails 6</em> added <code>#cache_versioning</code> for <code>ActiveRecord::Relation</code>.</p>
<p><code>ActiveRecord::Base.collection_cache_versioning</code> configuration should be enabled
to use cache versioning feature on collections. It is set to false by default.</p>
<p>We can enable this configuration as shown below.</p>
<pre><code class="language-ruby">
ActiveRecord::Base.collection_cache_versioning = true
# or
config.active_record.collection_cache_versioning = true

</code></pre>
<p>Before Rails 6, <code>ActiveRecord::Relation</code> had <code>cache_key</code> in format
<code>{table_name}/query-{query-hash}-{count}-{max(updated_at)}</code>.</p>
<p>In Rails 6, cache_key is split in stable part <code>cache_key</code> -
<code>{table_name}/query-{query-hash}</code> and volatile part <code>cache_version</code> -
<code>{count}-{max(updated_at)}</code>.</p>
<p>For more information, check out
<a href="https://blog.bigbinary.com/2016/02/02/activerecord-relation-cache-key.html">blog on ActiveRecord::Relation#cache_key in Rails 5</a>.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">
&gt;&gt; posts = Post.all

&gt;&gt; posts.cache_key
=&gt; &quot;posts/query-00644b6a00f2ed4b925407d06501c8fb-3-20190522172326885804&quot;

</code></pre>
<h4>Rails 6</h4>
<pre><code class="language-ruby">
&gt;&gt; ActiveRecord::Base.collection_cache_versioning = true

&gt;&gt; posts = Post.all

&gt;&gt; posts.cache_key
=&gt; &quot;posts/query-00644b6a00f2ed4b925407d06501c8fb&quot;

&gt;&gt; posts.cache_version
=&gt; &quot;3-20190522172326885804&quot;

</code></pre>
<p>Cache versioning works similarly for <code>ActiveRecord::Relation</code> as
<code>ActiveRecord::Base</code>.</p>
<p>In case of <code>ActiveRecord::Relation</code>, if number of records change and/or
record(s) are updated, then same <code>cache_key</code> is written to cache store with new
<code>cache_version</code> and updated records.</p>
<h2>Conclusion</h2>
<p>Previously, cache invalidation had to be done manually either by deleting cache
or setting cache expire duration. Cache versioning invalidates stale data
automatically and keeps latest copy of data, saving on storage and performance
drastically.</p>
<p>Check out the <a href="https://github.com/rails/rails/pull/29092">pull request</a> and
<a href="https://github.com/rails/rails/commit/4f2ac80d4cdb01c4d3c1765637bed76cc91c1e35">commit</a>
for more details.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 deprecates where.not as NOR & Rails 6.1 as NAND]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-deprecates-where-not-working-as-nor-and-will-change-to-nand-in-rails-6-1"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-deprecates-where-not-working-as-nor-and-will-change-to-nand-in-rails-6-1.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-deprecates-where-not-working-as-nor-and-will-change-to-nand-in-rails-6-1</id>
      <published>2019-07-31T00:00:00.000Z</published>
      <updated>2019-07-31T00:00:00.000Z</updated>
      <author>
        <name>Taha Husain</name>
        <uri>https://www.bigbinary.com/blog/authors/taha</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-deprecates-where-not-working-as-nor-and-will-change-to-nand-in-rails-6-1.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds a deprecation warning for where.not as NOR and will change in Rails 6.1 to NAND]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-deprecates-where-not-working-as-nor-and-will-change-to-nand-in-rails-6-1"><![CDATA[<p>A notable deprecation warning has been added in Rails 6 when using <code>where.not</code>
with multiple attributes.</p>
<p>Before Rails 6, if we use <code>where.not</code> with multiple attributes, it applies
logical <em>NOR (NOT(A) AND NOT(B))</em> in <em>WHERE</em> clause of the query. This does not
always work as expected.</p>
<p>Let's look at an example to understand this better.</p>
<p>We have <code>Post</code> model with a polymorphic association.</p>
<h5>Rails 5.2</h5>
<pre><code class="language-ruby">
&gt;&gt; Post.all
=&gt; #&lt;ActiveRecord::Relation [
#&lt;Post id: 1, title: &quot;First Post&quot;, source_type: &quot;Feed&quot;, source_id: 100&gt;,
#&lt;Post id: 2, title: &quot;Second Post&quot;, source_type: &quot;Feed&quot;, source_id: 101&gt;]&gt;

&gt;&gt; Post.where(source_type: &quot;Feed&quot;, source_id: 100)
=&gt; #&lt;ActiveRecord::Relation [#&lt;Post id: 1, title: &quot;First Post&quot;, source_type: &quot;Feed&quot;, source_id: 100&gt;]&gt;

&gt;&gt; Post.where.not(source_type: &quot;Feed&quot;, source_id: 100)
=&gt; #&lt;ActiveRecord::Relation []&gt;

</code></pre>
<p>In the last query, we expect ActiveRecord to fetch one record.</p>
<p>Let's check SQL generated for the above case.</p>
<pre><code class="language-ruby">
&gt;&gt; Post.where.not(source_type: &quot;Feed&quot;, source_id: 100).to_sql

=&gt; SELECT &quot;posts&quot;.* FROM &quot;posts&quot; WHERE &quot;posts&quot;.&quot;source_type&quot; != 'Feed' AND &quot;posts&quot;.&quot;source_id&quot; != 100

</code></pre>
<p><code>where.not</code> applies <em>AND</em> to the negation of <code>source_type</code> and <code>source_id</code>, and
fails to fetch expected records.</p>
<p>In such cases, correct implementation of <code>where.not</code> would be logical <em>NAND</em>
<em>(NOT(A) OR NOT(B))</em>.</p>
<p>Let us query <code>posts</code> table using NAND this time.</p>
<pre><code class="language-ruby">
&gt;&gt; Post.where(&quot;source_type != 'Feed' OR source_id != 100&quot;)

   SELECT &quot;posts&quot;.* FROM &quot;posts&quot; WHERE (source_type != 'Feed' OR source_id != 100)

=&gt; #&lt;ActiveRecord::Relation [#&lt;Post id: 2, title: &quot;Second Post&quot;, source_type: &quot;Feed&quot;, source_id: 101&gt;]&gt;

</code></pre>
<p>Above query works as expected and returns one record. Rails 6.1 will change
<code>where.not</code> working to NAND similar to the above query.</p>
<h5>Rails 6.0.0.rc1</h5>
<pre><code class="language-ruby">
&gt;&gt; Post.where.not(source_type: &quot;Feed&quot;, source_id: 100)

DEPRECATION WARNING: NOT conditions will no longer behave as NOR in Rails 6.1. To continue using NOR conditions, NOT each conditions manually (`.where.not(:source_type =&gt; ...).where.not(:source_id =&gt; ...)`). (called from irb_binding at (irb):1)

=&gt; #&lt;ActiveRecord::Relation []&gt;

</code></pre>
<p>It is well mentioned in deprecation warning that if we wish to use <em>NOR</em>
condition with multiple attributes, we can chain multiple <code>where.not</code> using a
single predicate.</p>
<pre><code class="language-ruby">
&gt;&gt; Post.where.not(source_type: &quot;Feed&quot;).where.not(source_id: 100)

</code></pre>
<p>Here's the relevant <a href="https://github.com/rails/rails/issues/31209">discussion</a>
and <a href="https://github.com/rails/rails/pull/36029">pull request</a> for this change.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds support for Optimizer Hints]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-supports-optimizer-hints"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-supports-optimizer-hints.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-supports-optimizer-hints</id>
      <published>2019-07-30T00:00:00.000Z</published>
      <updated>2019-07-30T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-supports-optimizer-hints.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 has added support for Optimizer Hints]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-supports-optimizer-hints"><![CDATA[<p>Rails 6 has added support to provide optimizer hints.</p>
<h2>What is Optimizer Hints?</h2>
<p>Many relational database management systems (RDBMS) have a query optimizer. The
job of the query optimizer is to determine the most efficient and fast plan to
execute a given SQL query. Query optimizer has to consider all possible query
execution plans before it can determine which plan is the optimal plan for
executing the given SQL query and then compile and execute that query.</p>
<p>An optimal plan is chosen by the query optimizer by calculating the cost of each
possible plans. Typically, when the number of tables referenced in a join query
increases, then the time spent in query optimization grows exponentially which
often affects the system's performance. The fewer the execution plans the query
optimizer needs to evaluate, the lesser time is spent in compiling and executing
the query.</p>
<p>As an application designer, we might have more context about the data stored in
our database. With the contextual knowledge about our database, we might be able
to choose a more efficient execution plan than the query optimizer.</p>
<p>This is where the optimizer hints or optimizer guidelines come into picture.</p>
<p>Optimizer hints allow us to control the query optimizer to choose a certain
query execution plan based on the specific criteria. In other words, we can hint
the optimizer to use or ignore certain optimization plans using optimizer hints.</p>
<p>Usually, optimizer hints should be provided only when executing a complex query
involving multiple table joins.</p>
<p>Note that the optimizer hints only affect an individual SQL statement. To alter
the optimization strategies at the global level, there are different mechanisms
supported by different databases. Optimizer hints provide finer control over
other mechanisms which allow altering optimization plans by other means.</p>
<p>Optimizer hints are supported by many databases such as
<a href="https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html">MySQL</a>,
<a href="https://pghintplan.osdn.jp/pg_hint_plan.html">PostgreSQL with the help of <code>pg_hint_plan</code> extension</a>,
<a href="https://docs.oracle.com/en/database/oracle/oracle-database/12.2/tgsql/influencing-the-optimizer.html">Oracle</a>,
<a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-query?view=sql-server-2017">MS SQL</a>,
<a href="https://www.ibm.com/support/knowledgecenter/en/SSEPGG_11.1.0/com.ibm.db2.luw.admin.perf.doc/doc/c0070117.html">IBM DB2</a>,
etc. with varying syntax and options.</p>
<h2>Optimizer Hints in Rails 6</h2>
<p>Before Rails 6, we have to execute a raw SQL query to use the optimizer hints.</p>
<pre><code class="language-ruby">query = &quot;SELECT
            /*+ JOIN_ORDER(articles, users) MAX_EXECUTION_TIME(60000) */
            articles.*
         FROM articles
         INNER JOIN users
         ON users.id = articles.user_id
         WHERE (published_at &gt; '2019-02-17 13:15:44')
        &quot;.squish

ActiveRecord::Base.connection.execute(query)
</code></pre>
<p>In the above query, we provided two optimizer hints to MySQL .</p>
<pre><code class="language-plaintext">/*+ HINT_HERE ANOTHER_HINT_HERE ... */
</code></pre>
<p>Another approach to use optimizer hints prior to Rails 6 is to
<a href="https://gist.github.com/kamipo/4c8539f0ce4acf85075cf5a6b0d9712e">use a monkey patch like this</a>.</p>
<p>In Rails 6, using optimizer hints is easier.</p>
<p>The same example looks like this in Rails 6.</p>
<pre><code class="language-ruby">Article
  .joins(:user)
  .where(&quot;published_at &gt; ?&quot;, 2.months.ago)
  .optimizer_hints(
    &quot;JOIN_ORDER(articles, users)&quot;,
    &quot;MAX_EXECUTION_TIME(60000)&quot;
  )
</code></pre>
<p>This produces the same SQL query as above but the result is of type
<code>ActiveRecord::Relation</code>.</p>
<p>In PostgreSQL (using the <code>pg_hint_plan</code> extension), the optimizer hints have a
different syntax.</p>
<pre><code class="language-ruby">Article
  .joins(:user)
  .where(&quot;published_at &gt; ?&quot;, 2.months.ago)
  .optimizer_hints(&quot;Leading(articles users)&quot;, &quot;SeqScan(articles)&quot;)
</code></pre>
<p>Please checkout the documentation of each database separately to learn the
support and syntax of optimizer hints.</p>
<p>To learn more, please
<a href="https://github.com/rails/rails/pull/35615">checkout this PR</a> which introduced
the <code>#optimization_hints</code> method to Rails 6.</p>
<h2>Bonus example: Using optimizer hints to speedup a slow SQL statement in MySQL</h2>
<p>Consider that we have <code>articles</code> table with some indexes.</p>
<pre><code class="language-ruby">class CreateArticles &lt; ActiveRecord::Migration[6.0]
  def change
    create_table :articles do |t|
      t.string :title, null: false
      t.string :slug, null: false
      t.references :user
      t.datetime :published_at
      t.text :description

      t.timestamps

      t.index :slug, unique: true
      t.index [:published_at]
      t.index [:slug, :user_id]
      t.index [:published_at, :user_id]
      t.index [:title, :slug]
    end
  end
end
</code></pre>
<p>Let's try to fetch all the articles which have been published in the last 2
months.</p>
<pre><code class="language-ruby">&gt;&gt; Article.joins(:user).where(&quot;published_at &gt; ?&quot;, 2.months.ago)
# Article Load (10.5ms)  SELECT `articles`.* FROM `articles` INNER JOIN `users` ON `users`.`id` = `articles`.`user_id` WHERE (published_at &gt; '2019-02-17 11:38:18.647296')
=&gt; #&lt;ActiveRecord::Relation [#&lt;Article id: 20, title: &quot;Article 20&quot;, slug: &quot;article-20&quot;, user_id: 1, ...]&gt;
</code></pre>
<p>Let's use <code>EXPLAIN</code> to investigate why it is taking 10.5ms to execute this
query.</p>
<pre><code class="language-ruby">&gt;&gt; Article.joins(:user).where(&quot;published_at &gt; ?&quot;, 2.months.ago).explain
# Article Load (13.9ms)  SELECT `articles`.* FROM `articles` INNER JOIN `users` ON `users`.`id` = `articles`.`user_id` WHERE (published_at &gt; '2019-02-17 11:39:05.380577')
=&gt; # EXPLAIN for: SELECT `articles`.* FROM `articles` INNER JOIN `users` ON `users`.`id` = `articles`.`user_id` WHERE (published_at &gt; '2019-02-17 11:39:05.380577')
# +--------+----------+----------------+-----------+------+----------+-------+
# | select |   table  | possible_keys  | key       | rows | filtered | Extra |
# | _type  |          |                |           |      |          |       |
# +--------+----------+----------------+-----------+------+----------+-------+
# | SIMPLE |   users  | PRIMARY        | PRIMARY   | 2    | 100.0    | Using |
# |        |          |                |           |      |          | index |
# +--------+----------+----------------+-----------+------+----------+-------+
# | SIMPLE | articles | index          | index     | 9866 | 10.0     | Using |
# |        |          | _articles      | _articles |      |          | where |
# |        |          | _on_user_id,   | _on       |      |          |       |
# |        |          | index          | _user_id  |      |          |       |
# |        |          | _articles      |           |      |          |       |
# |        |          | _on            |           |      |          |       |
# |        |          | _published_at, |           |      |          |       |
# |        |          | index          |           |      |          |       |
# |        |          | _articles      |           |      |          |       |
# |        |          | _on            |           |      |          |       |
# |        |          | _published_at  |           |      |          |       |
# |        |          | _and_user_id   |           |      |          |       |
# +--------+----------+----------------+-----------+------+----------+-------+
</code></pre>
<p>According to the above table, it appears that the query optimizer is considering
<code>users</code> table first and then the <code>articles</code> table.</p>
<p>The <code>rows</code> column indicates the estimated number of rows the query optimizer
must examine to execute the query.</p>
<p>The
<a href="https://dev.mysql.com/doc/refman/8.0/en/explain-output.html#explain_filtered"><code>filtered</code></a>
column indicates an estimated percentage of table rows that will be filtered by
the table condition.</p>
<p>The formula <code>rows x filtered</code> gives the number of rows that will be joined with
the following table.</p>
<p>Also,</p>
<ul>
<li>For <code>users</code> table, the number of rows to be joined with the following table is
<code>2 x 100% = 2</code>,</li>
<li>For <code>articles</code> table, the number of rows to be joined with the following table
is <code>500 * 7.79 = 38.95</code>.</li>
</ul>
<p>Since the <code>articles</code> tables contain more records which references very few
records from the <code>users</code> table, it would be better to consider the <code>articles</code>
table first and then the <code>users</code> table.</p>
<p>We can hint MySQL to consider the <code>articles</code> table first as follows.</p>
<pre><code class="language-ruby">&gt;&gt; Article.joins(:user).where(&quot;published_at &gt; ?&quot;, 2.months.ago).optimizer_hints(&quot;JOIN_ORDER(articles, users)&quot;)
# Article Load (2.2ms)  SELECT `articles`.* FROM `articles` INNER JOIN `users` ON `users`.`id` = `articles`.`user_id` WHERE (published_at &gt; '2019-02-17 11:54:06.230651')
=&gt; #&lt;ActiveRecord::Relation [#&lt;Article id: 20, title: &quot;Article 20&quot;, slug: &quot;article-20&quot;, user_id: 1, ...]&gt;
</code></pre>
<p>Note that it took 2.2ms now to fetch the same records by providing
<code>JOIN_ORDER(articles, users)</code> optimization hint.</p>
<p>Let's try to <code>EXPLAIN</code> what changed by using this <code>JOIN_ORDER(articles, users)</code>
optimization hint.</p>
<pre><code class="language-ruby">&gt;&gt; Article.joins(:user).where(&quot;published_at &gt; ?&quot;, 2.months.ago).optimizer_hints(&quot;JOIN_ORDER(articles, users)&quot;).explain
# Article Load (4.1ms)  SELECT /*+ JOIN_ORDER(articles, users) */ `articles`.* FROM `articles` INNER JOIN `users` ON `users`.`id` = `articles`.`user_id` WHERE (published_at &gt; '2019-02-17 11:55:24.335152')
=&gt; # EXPLAIN for: SELECT /*+ JOIN_ORDER(articles, users) */ `articles`.* FROM `articles` INNER JOIN `users` ON `users`.`id` = `articles`.`user_id` WHERE (published_at &gt; '2019-02-17 11:55:24.335152')
# +--------+----------+----------------+-----------+------+----------+--------+
# | select |   table  | possible_keys  | key       | rows | filtered | Extra  |
# | _type  |          |                |           |      |          |        |
# +--------+----------+----------------+-----------+------+----------+--------+
# | SIMPLE | articles | index          | index     | 769  | 100.0    | Using  |
# |        |          | _articles      | _articles |      |          | index  |
# |        |          | _on_user_id,   | _on       |      |          | condi  |
# |        |          | index          | _publish  |      |          | tion;  |
# |        |          | _articles      | ed_at,    |      |          | Using  |
# |        |          | _on            |           |      |          | where  |
# |        |          | _published_at, |           |      |          |        |
# |        |          | index          |           |      |          |        |
# |        |          | _articles      |           |      |          |        |
# |        |          | _on            |           |      |          |        |
# |        |          | _published_at  |           |      |          |        |
# |        |          | _and_user_id   |           |      |          |        |
# +--------+----------+----------------+-----------+------+----------+--------+
# | SIMPLE | users    | PRIMARY        | PRIMARY   | 2    | 100.0    | Using  |
# |        |          |                |           |      |          | index  |
# +--------+----------+----------------+-----------+------+----------+--------+
</code></pre>
<p>The result of the <code>EXPLAIN</code> query shows that the <code>articles</code> table was considered
first and then the <code>users</code> table as expected. We can also see that the
<code>index_articles_on_published_at</code> index key was considered from the possible keys
to execute the given query. The <code>filtered</code> column for both tables shows that the
number of filtered rows was 100% which means no filtering of rows occurred.</p>
<p>We hope this example helps in understanding how to use <code>#explain</code> and
<code>#optimization_hints</code> methods in order to investigate and debug the performance
issues and then fixing it.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 reports object allocations while rendering]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-reports-object-allocations-made-while-rendering-view-templates"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-reports-object-allocations-made-while-rendering-view-templates.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-reports-object-allocations-made-while-rendering-view-templates</id>
      <published>2019-07-23T00:00:00.000Z</published>
      <updated>2019-07-23T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-reports-object-allocations-made-while-rendering-view-templates.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 reports object allocations made while rendering view templates]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-reports-object-allocations-made-while-rendering-view-templates"><![CDATA[<p>Recently, Rails 6
<a href="https://github.com/rails/rails/pull/33449">added <code>allocations</code> feature</a> to
<code>ActiveSupport::Notifications::Event</code>. Using this feature, an event subscriber
can see how many number of objects were allocated during the event's start time
and end time. We have written in detail about this feature
<a href="https://blog.bigbinary.com/2019/04/24/rails-6-adds-cpu-time-idle-time-and-allocations-to-activesupport-notifications-event.html">here</a>.</p>
<p>By taking the benefit of this feature, Rails 6 now reports the allocations made
while rendering a view template, a partial and a collection.</p>
<pre><code class="language-plaintext">Started GET &quot;/articles&quot; for ::1 at 2019-04-15 17:24:09 +0530
Processing by ArticlesController#index as HTML
Rendering articles/index.html.erb within layouts/application
Rendered shared/\_ad_banner.html.erb (Duration: 0.1ms | Allocations: 6)
Article Load (1.3ms) SELECT &quot;articles&quot;.\* FROM &quot;articles&quot;
↳ app/views/articles/index.html.erb:5
Rendered collection of articles/\_article.html.erb [100 times] (Duration: 6.1ms | Allocations: 805)
Rendered articles/index.html.erb within layouts/application (Duration: 17.6ms | Allocations: 3901)
Completed 200 OK in 86ms (Views: 83.6ms | ActiveRecord: 1.3ms | Allocations: 29347)
</code></pre>
<p>Notice the <code>Allocations:</code> information in the above logs.</p>
<p>We can see that</p>
<ul>
<li>6 objects were allocated while rendering <code>shared/_ad_banner.html.erb</code> view
partial,</li>
<li>805 objects were allocated while rendering a collection of 100
<code>articles/_article.html.erb</code> view partials,</li>
<li>and 3901 objects were allocated while rendering <code>articles/index.html.erb</code> view
template.</li>
</ul>
<p>We can use this information to understand how much time was spent while
rendering a view template and how many objects were allocated in the process'
memory between the time when that view template had started rendering and the
time when that view template had finished rendering.</p>
<p>To learn more about this feature, please check
<a href="https://github.com/rails/rails/pull/34136">rails/rails#34136</a>.</p>
<p>Note that we can also collect this information by subscribing to
<a href="https://edgeguides.rubyonrails.org/active_support_instrumentation.html#action-view">Action View hooks</a>.</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe /^render\_.+.action_view\$/ do |event|
views_path = Rails.root.join(&quot;app/views/&quot;).to_s
template_identifier = event.payload[:identifier]
template_name = template_identifier.sub(views_path, &quot;&quot;)
message = &quot;[#{event.name}] #{template_name} (Allocations: #{event.allocations})&quot;

ViewAllocationsLogger.log(message)
end
</code></pre>
<p>This should log something like this.</p>
<pre><code class="language-plaintext">[render_partial.action_view] shared/\_ad_banner.html.erb (Allocations: 43)

[render_collection.action_view] articles/\_article.html.erb (Allocations: 842)

[render_template.action_view] articles/index.html.erb (Allocations: 4108)
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActiveRecord::Relation#annotate]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-annotate-to-activerecord-relation-queries"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-annotate-to-activerecord-relation-queries.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-annotate-to-activerecord-relation-queries</id>
      <published>2019-07-15T00:00:00.000Z</published>
      <updated>2019-07-15T00:00:00.000Z</updated>
      <author>
        <name>Abhay Nikam</name>
        <uri>https://www.bigbinary.com/blog/authors/abhay</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-annotate-to-activerecord-relation-queries.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds ActiveRecord::Relation#annotate to annotate generated SQL queries]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-annotate-to-activerecord-relation-queries"><![CDATA[<p>Rails 6 has added <code>ActiveRecord::Relation#annotate</code> to allow adding comments to
the SQL queries generated by the <code>ActiveRecord::Relation</code> instance.</p>
<p>Here is how it can be used.</p>
<pre><code class="language-ruby">
&gt; &gt; User.annotate(&quot;User whose name starts with 'A'&quot;).where(&quot;name LIKE ?&quot;, &quot;A%&quot;)

SELECT &quot;users&quot;._ FROM &quot;users&quot;
WHERE (name LIKE 'A%')
/_ User whose name starts with 'A' \*/
LIMIT ? [[&quot;LIMIT&quot;, 11]]
</code></pre>
<p><code>ActiveRecord::Relation#annotate</code> allows to add multiple annotations on a query</p>
<pre><code class="language-ruby">
&gt; &gt; bigbinary = Organization.find_by!(name: &quot;BigBinary&quot;)
&gt; &gt; User.annotate(&quot;User whose name starts with 'A'&quot;)

       .annotate(&quot;AND belongs to BigBinary organization&quot;)
       .where(&quot;name LIKE ?&quot;, &quot;A%&quot;)
       .where(organization: bigbinary)

SELECT &quot;users&quot;._ FROM &quot;users&quot;
WHERE (name LIKE 'A%') AND &quot;users&quot;.&quot;organization_id&quot; = ?
/_ Users whose name starts with 'A' _/
/_ AND belongs to BigBinary organization \*/
LIMIT ? [[&quot;organization_id&quot;, 1], [&quot;LIMIT&quot;, 11]]
</code></pre>
<p>Also, <code>ActiveRecord::Relation#annotate</code> allows annotating scopes and model
associations.</p>
<pre><code class="language-ruby">class User &lt; ActiveRecord::Base
scope :active, -&gt; { where(status: 'active').annotate(&quot;Active users&quot;) }
end

&gt; &gt; User.active
&gt; &gt; SELECT &quot;users&quot;._ FROM &quot;users&quot;
&gt; &gt; /_ Active users \*/
&gt; &gt; LIMIT ? [[&quot;LIMIT&quot;, 11]]
&gt; &gt; ~~~

Check out the
[pull request](https://github.com/rails/rails/pull/35617)
for more details on this.
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds hook to Active Job for retry & discard]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-hooks-to-activejob-around-retries-and-discards"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-hooks-to-activejob-around-retries-and-discards.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-hooks-to-activejob-around-retries-and-discards</id>
      <published>2019-07-09T00:00:00.000Z</published>
      <updated>2019-07-09T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-hooks-to-activejob-around-retries-and-discards.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds hooks to Active Job around retries and discards]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-hooks-to-activejob-around-retries-and-discards"><![CDATA[<h2>Before Rails 6</h2>
<p>Before Rails 6, we have to provide a custom block to perform custom logging and
monitoring around retries and discards of the jobs defined using Active Job
framework.</p>
<pre><code class="language-ruby">class Container::DeleteJob &lt; ActiveJob::Base
retry_on Timeout::Error, wait: 2.seconds, attempts: 3 do |job, error|
message = &quot;Stopped retrying #{job.class} (JID #{job.job_id})
with #{job.arguments.join(', ')} due to
'#{error.class} - #{error.message}'.
This job was retried for #{job.executions} times.&quot;.squish

    BackgroundJob::ErrorLogger.log(message)

end

discard_on Container::NotFoundError do |job, error|
message = &quot;Discarded #{job.class} (JID #{job.job_id})
with #{job.arguments.join(', ')} due to
'#{error.class} - #{error.message}' error.&quot;.squish

    BackgroundJob::ErrorLogger.log(message)

end

def perform(container_id)
Container::DeleteService(container_id).process

    # Will raise Container::NotFoundError
    # if no container is found with 'container_id'.

    # Might raise Timeout::Error when the remote API is not responding.

end
end
</code></pre>
<p>Notice the custom blocks provided to <code>retry_on</code> and <code>discard_on</code> methods to an
individual job in the above example.</p>
<p>Extracting such custom logic to a base class or to a 3rd-party gem is possible
but it will be non-standard and will be a bit difficult task.</p>
<p>An alternative approach is to
<a href="https://guides.rubyonrails.org/active_support_instrumentation.html#subscribing-to-an-event">subscribe</a>
to the hooks instrumented using Active Support Instrumentation API which is a
standard and recommended way. Prior versions of Rails 6 already instruments
<a href="https://guides.rubyonrails.org/v5.2/active_support_instrumentation.html#active-job">some hooks</a>
such as <code>enqueue_at.active_job</code>, <code>enqueue.active_job</code>,
<code>perform_start.active_job</code>, and <code>perform.active_job</code>. Unfortunately no hook is
instrumented around retries and discards of an Active Job prior to Rails 6.</p>
<h2>Rails 6</h2>
<p>Rails 6 has introduced hooks to Active Job
<a href="https://github.com/rails/rails/pull/33751">around retries and discards</a> to
which one can easily subscribe using Active Support Instrumentation API to
perform custom logging and monitoring or to collect any custom information.</p>
<p>The newly introduced hooks are <code>enqueue_retry.active_job</code>,
<code>retry_stopped.active_job</code> and <code>discard.active_job</code>.</p>
<p>Let's discuss each of these hooks in detail.</p>
<p>Note that whenever we say <code>a job</code>, it means a job of type <code>ActiveJob</code>.</p>
<h5><code>enqueue_retry.active_job</code></h5>
<p>The <code>enqueue_retry.active_job</code> hook is instrumented when a job is
<a href="https://github.com/rails/rails/blob/2ab3751781e34ca4a8d477ba53ff307ae9884b0d/activejob/lib/active_job/exceptions.rb#L119-L123">enqueued to retry again</a>
due to occurrence of an exception which is configured using the <code>retry_on</code>
method in the job's definition. This hook is triggered only when above condition
is satisfied and the number of executions of the job is less than the number of
<code>attempts</code> defined using the <code>retry_on</code> method. The number of <code>attempts</code> is by
default set to 5 if not defined explicitly.</p>
<p>This is how we would subscribe to this hook and perform custom logging in our
Rails application.</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe &quot;enqueue_retry.active_job&quot; do |*args|
event = ActiveSupport::Notifications::Event.new *args
payload = event.payload
job = payload[:job]
error = payload[:error]
message = &quot;#{job.class} (JID #{job.job_id})
with arguments #{job.arguments.join(', ')}
will be retried again in #{payload[:wait]}s
due to error '#{error.class} - #{error.message}'.
It is executed #{job.executions} times so far.&quot;.squish

BackgroundJob::Logger.log(message)
end
</code></pre>
<p>Note that the <code>BackgroundJob::Logger</code> above is our custom logger. If we want, we
can add any other logic instead.</p>
<p>We will change the definition of <code>Container::DeleteJob</code> job as below.</p>
<pre><code class="language-ruby">class Container::DeleteJob &lt; ActiveJob::Base
retry_on Timeout::Error, wait: 2.seconds, attempts: 3

def perform(container_id)
Container::DeleteService(container_id).process

    # Will raise Timeout::Error when the remote API is not responding.

end
end
</code></pre>
<p>Let's enqueue this job.</p>
<pre><code class="language-ruby">Container::DeleteJob.perform_now(&quot;container-1234&quot;)
</code></pre>
<p>Assume that this job keeps throwing <code>Timeout::Error</code> exception due to a network
issue. The job will be retried twice since it is configured to retry when a
<code>Timeout::Error</code> exception occurs up to maximum 3 attempts. While retrying this
job, Active Job will instrument <code>enqueue_retry.active_job</code> hook along with the
necessary job payload.</p>
<p>Since we have already subscribed to this hook, our subscriber would log
something like this with the help of <code>BackgroundJob::Logger.log</code>.</p>
<pre><code class="language-plaintext">Container::DeleteJob (JID 770f4f2a-daa7-4c1e-be51-24adc04b4cb2) with arguments container-1234 will be retried again in 2s due to error 'Timeout::Error - Couldn't establish connection to cluster within 10s'. It is executed 1 times so far.

Container::DeleteJob (JID 770f4f2a-daa7-4c1e-be51-24adc04b4cb2) with arguments container-1234 will be retried again in 2s due to error 'Timeout::Error - Couldn't establish connection to cluster within 10s'. It is executed 2 times so far.
</code></pre>
<h5><code>retry_stopped.active_job</code></h5>
<p>The <code>retry_stopped.active_job</code> hook is triggered when a job is retried
<a href="https://github.com/rails/rails/blob/2ab3751781e34ca4a8d477ba53ff307ae9884b0d/activejob/lib/active_job/exceptions.rb#L59-L66">up to the available number of <code>attempts</code></a>.</p>
<p>Let's see how this hook is triggered.</p>
<p>Along with the subscription for the <code>enqueue_retry.active_job</code> hook, let's
subscribe to the <code>retry_stopped.active_job</code> hook, too.</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe &quot;retry_stopped.active_job&quot; do |*args|
event = ActiveSupport::Notifications::Event.new *args
payload = event.payload
job = payload[:job]
error = payload[:error]
message = &quot;Stopped processing #{job.class} (JID #{job.job_id})
further with arguments #{job.arguments.join(', ')}
since it failed due to '#{error.class} - #{error.message}' error
which reoccurred #{job.executions} times.&quot;.squish

BackgroundJob::Logger.log(message)
end
</code></pre>
<p>Let's keep the <code>Container::DeleteJob</code> job's definition unchanged and enqueue it
again.</p>
<pre><code class="language-ruby">Container::DeleteJob.perform_now(&quot;container-1234&quot;)
</code></pre>
<p>We will assume that the job will keep throwing <code>Timeout::Error</code> exception due to
a network issue.</p>
<p>In the logs recorded using <code>BackgroundJob::Logger.log</code>, we should see something
like this.</p>
<pre><code class="language-plaintext">Container::DeleteJob (JID 770f4f2a-daa7-4c1e-be51-24adc04b4cb2) with arguments container-1234 will be retried again in 2s due to error 'Timeout::Error - Couldn't establish connection to cluster within 10s'. It is executed 1 times so far.

Container::DeleteJob (JID 770f4f2a-daa7-4c1e-be51-24adc04b4cb2) with arguments container-1234 will be retried again in 2s due to error 'Timeout::Error - Couldn't establish connection to cluster within 10s'. It is executed 2 times so far.

Stopped processing Container::DeleteJob (JID 770f4f2a-daa7-4c1e-be51-24adc04b4cb2) further with arguments container-1234 since it failed due to 'Timeout::Error - Couldn't establish connection to cluster within 10s' error which reoccurred 3 times.
</code></pre>
<p>Notice the last entry in the logs above and its order.</p>
<h5><code>discard.active_job</code></h5>
<p>The <code>discard.active_job</code> hook is triggered when a job's further execution is
discarded due to occurrence of an exception which is configured using
<code>discard_on</code> method.</p>
<p>To see how this hook is triggered, we will subscribe to the <code>discard.active_job</code>
hook.</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe &quot;discard.active_job&quot; do |*args|
event = ActiveSupport::Notifications::Event.new *args
payload = event.payload
job = payload[:job]
error = payload[:error]
message = &quot;Discarded #{job.class} (JID #{job.job_id})
with arguments #{job.arguments.join(', ')}
due to '#{error.class} - #{error.message}' error.&quot;.squish

BackgroundJob::Logger.log(message)
end
</code></pre>
<p>We will configure our <code>Container::DeleteJob</code> job to discard when
<code>Container::NotFoundError</code> exception occurs while executing the job.</p>
<pre><code class="language-ruby">class Container::DeleteJob &lt; ActiveJob::Base
discard_on Container::NotFoundError
retry_on Timeout::Error, wait: 2.seconds, attempts: 3

def perform(container_id)
Container::DeleteService(container_id).process

    # Will raise Container::NotFoundError
    # if no container is found with 'container_id'.

    # Will raise Timeout::Error when the remote API is not responding.

end
end
</code></pre>
<p>Let's enqueue this job and assume that it would throw <code>Container::NotFoundError</code>
exception.</p>
<pre><code class="language-ruby">Container::DeleteJob.perform_now(&quot;unknown-container-9876&quot;)
</code></pre>
<p>We should see following in the logs recorded by <code>BackgroundJob::Logger.log</code>.</p>
<pre><code class="language-plaintext">Discarded Container::DeleteJob (JID e9b1cb5c-6d2d-49ae-b1d7-fef44f09ab8d) with arguments unknown-container-9876 due to 'Container::NotFoundError - Container 'unknown-container-9876' was not found' error.
</code></pre>
<h2>Notes</h2>
<ol>
<li>
<p>These new hooks are also instrumented for the jobs which are enqueued using
<code>perform_later</code> method since both <code>perform_now</code> and <code>perform_later</code> calls
<code>perform</code> method under the hood.</p>
</li>
<li>
<p>Active Job already subscribes to the these hooks and writes them using the
<a href="https://github.com/rails/rails/blob/2ab3751781e34ca4a8d477ba53ff307ae9884b0d/activejob/lib/active_job/logging.rb#L91-L121">Rails' default logger</a>.</p>
</li>
<li>
<p>If a block is provided to <code>retry_on</code> or <code>discard_on</code> methods then an
applicable hook is instrumented first and then the given block is yielded.</p>
</li>
</ol>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds support for Multi Environment credentials]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-support-for-multi-environment-credentials"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-support-for-multi-environment-credentials.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-support-for-multi-environment-credentials</id>
      <published>2019-07-03T00:00:00.000Z</published>
      <updated>2019-07-03T00:00:00.000Z</updated>
      <author>
        <name>Berin Larson</name>
        <uri>https://www.bigbinary.com/blog/authors/berinlarson</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-support-for-multi-environment-credentials.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[In Rails 5.2, encrypted credentials are stored in the file config/credentials.yml.enc. This is a single flat file which is encrypted by the key located in config/master.key. Rails 5.2 does not...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-support-for-multi-environment-credentials"><![CDATA[<p>In Rails 5.2, encrypted credentials are stored in the file
<code>config/credentials.yml.enc</code>. This is a single flat file which is encrypted by
the key located in <code>config/master.key</code>.</p>
<p>Rails 5.2 does not support storing credentials of different environments with
different encryption keys. If we want environment specific encrypted
credentials, we'll have to follow
<a href="https://github.com/rails/rails/pull/33521#issuecomment-449403068">this workaround</a>.</p>
<p>Rails 6 has added support for Multi Environment credentials. With this change,
credentials that belong to different environments can be stored in separate
files with their own encryption key.</p>
<p>Let's see how this works in Rails 6.0.0.beta3</p>
<h2>Rails 6.0.0.beta3</h2>
<p>If we want to add credentials to be used in staging environment, we can run</p>
<pre><code class="language-bash">rails credentials:edit --environment staging
</code></pre>
<p>This will create the credentials file <code>config/credentials/staging.yml.enc</code> and a
staging specific encryption key <code>config/credentials/staging.key</code> and open the
credentials file in your text editor.</p>
<p>Let's add our AWS access key id here.</p>
<pre><code class="language-yaml">aws:
  access_key_id: &quot;STAGING_KEY&quot;
</code></pre>
<p>We can then access the access_key_id in staging environment.</p>
<pre><code class="language-ruby">
&gt;&gt; RAILS_ENV=staging rails c

pry(main)&gt; Rails.application.credentials.aws[:access_key_id]

=&gt; &quot;STAGING_KEY&quot;

</code></pre>
<h2>Which takes precedence: Global or Environment Specific credentials?</h2>
<p>Credentials added to global file <code>config/credentials.yml.enc</code>
<a href="https://github.com/rails/rails/pull/33521#issuecomment-412382031">will not be loaded</a>
in environments which have their own environment specific credentials file
(<code>config/credentials/$environment.yml.enc</code>).</p>
<p>So if we decide to add the following to the global credentials file, these
credentials will not be available in staging. Since we already have a
environment specific credentials file for staging.</p>
<pre><code class="language-yaml">aws:
  access_key_id: &quot;DEFAULT_KEY&quot;
stripe:
  secret_key: &quot;DEFAULT_SECRET_KEY&quot;
</code></pre>
<pre><code class="language-ruby">
&gt;&gt; RAILS_ENV=staging rails c

pry(main)&gt; Rails.application.credentials.aws[:access_key_id]

=&gt; &quot;STAGING_KEY&quot;

pry(main)&gt; Rails.application.credentials.stripe[:secret_key]

Traceback (most recent call last):
        1: from (irb):6
NoMethodError (undefined method `[]' for nil:NilClass)

</code></pre>
<p>Here is the <a href="https://github.com/rails/rails/pull/33521">relevant pull request</a></p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds before? and after? to Date and Time]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-before-and-after-to-date-and-time"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-before-and-after-to-date-and-time.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-before-and-after-to-date-and-time</id>
      <published>2019-06-26T00:00:00.000Z</published>
      <updated>2019-06-26T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-before-and-after-to-date-and-time.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds before? and after? to Date, DateTime, Time and ActiveSupport::TimeWithZone classes]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-before-and-after-to-date-and-time"><![CDATA[<p>Rails 6 adds <a href="https://github.com/rails/rails/pull/32185">before?</a> and
<a href="https://github.com/rails/rails/pull/32185">after?</a> to
<a href="https://api.rubyonrails.org/v5.2/classes/Date.html">Date</a> ,
<a href="https://api.rubyonrails.org/v5.2/classes/DateTime.html">DateTime</a> ,
<a href="https://api.rubyonrails.org/v5.2/classes/Time.html">Time</a> and
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/TimeWithZone.html">ActiveSupport::TimeWithZone</a>
classes.</p>
<p><a href="https://github.com/rails/rails/pull/32185">before?</a> and
<a href="https://github.com/rails/rails/pull/32185">after?</a> are aliases to
<a href="https://api.rubyonrails.org/v5.2/classes/Date.html#method-i-3C-3D-3E">&lt; (less than)</a>
and
<a href="https://api.rubyonrails.org/v5.2/classes/Date.html#method-i-3C-3D-3E">&gt; (greater than)</a>
methods respectively.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<p>Let's try calling <code>before?</code> on a date object in Rails 5.2.</p>
<pre><code class="language-ruby">
&gt; &gt; Date.new(2019, 3, 31).before?(Date.new(2019, 4, 1))

=&gt; NoMethodError: undefined method 'before?' for Sun, 31 Mar 2019:Date
from (irb):1

&gt; &gt; Date.new(2019, 3, 31) &lt; Date.new(2019, 4, 1)

=&gt; true
</code></pre>
<h4>Rails 6.0.0.beta2</h4>
<p>Now, let's compare <a href="https://api.rubyonrails.org/v5.2/classes/Date.html">Date</a> ,
<a href="https://api.rubyonrails.org/v5.2/classes/DateTime.html">DateTime</a> ,
<a href="https://api.rubyonrails.org/v5.2/classes/Time.html">Time</a> and
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/TimeWithZone.html">ActiveSupport::TimeWithZone</a>
objects using <a href="https://github.com/rails/rails/pull/32185">before?</a> and
<a href="https://github.com/rails/rails/pull/32185">after?</a> in Rails 6.</p>
<pre><code class="language-ruby">
&gt; &gt; Date.new(2019, 3, 31).before?(Date.new(2019, 4, 1))

=&gt; true

&gt; &gt; Date.new(2019, 3, 31).after?(Date.new(2019, 4, 1))

=&gt; false

&gt; &gt; DateTime.parse('2019-03-31').before?(DateTime.parse('2019-04-01'))

=&gt; true

&gt; &gt; DateTime.parse('2019-03-31').after?(DateTime.parse('2019-04-01'))

=&gt; false

&gt; &gt; Time.parse('2019-03-31').before?(Time.parse('2019-04-01'))

=&gt; true

&gt; &gt; Time.parse('2019-03-31').after?(Time.parse('2019-04-01'))

=&gt; false

&gt; &gt; ActiveSupport::TimeWithZone.new(Time.utc(2019, 3, 31, 12, 0, 0), ActiveSupport::TimeZone[&quot;Eastern Time (US &amp; Canada)&quot;]).before?(ActiveSupport::TimeWithZone.new(Time.utc(2019, 4, 1, 12, 0, 0), ActiveSupport::TimeZone[&quot;Eastern Time (US &amp; Canada)&quot;]))

=&gt; true

&gt; &gt; ActiveSupport::TimeWithZone.new(Time.utc(2019, 3, 31, 12, 0, 0), ActiveSupport::TimeZone[&quot;Eastern Time (US &amp; Canada)&quot;]).after?(ActiveSupport::TimeWithZone.new(Time.utc(2019, 4, 1, 12, 0, 0), ActiveSupport::TimeZone[&quot;Eastern Time (US &amp; Canada)&quot;]))

=&gt; false
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/32185">pull request</a>
for adding <code>before?</code> and <code>after?</code> methods and the
<a href="https://github.com/rails/rails/pull/32398">pull request</a> for moving <code>before?</code>
and <code>after?</code> to
<a href="https://api.rubyonrails.org/v5.2/classes/DateAndTime/Calculations.html">DateAndTime::Calculations</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds Array#extract!]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-array-extract"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-array-extract.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-array-extract</id>
      <published>2019-06-24T00:00:00.000Z</published>
      <updated>2019-06-24T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-array-extract.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 added extract! on Array class. extract! removes and returns the elements for which the given block returns true. extract! is different from reject! in the way that reject! returns the array...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-array-extract"><![CDATA[<p>Rails 6 added <a href="https://github.com/rails/rails/pull/33137">extract!</a> on
<a href="https://api.rubyonrails.org/v5.2/classes/Array.html">Array</a> class.
<a href="https://github.com/rails/rails/pull/33137">extract!</a> removes and returns the
elements for which the given block returns true.</p>
<p><a href="https://github.com/rails/rails/pull/33137">extract!</a> is different from
<a href="https://ruby-doc.org/core-2.5.1/Array.html#method-i-reject-21">reject!</a> in the
way that
<a href="https://ruby-doc.org/core-2.5.1/Array.html#method-i-reject-21">reject!</a> returns
the array after removing the elements whereas
<a href="https://github.com/rails/rails/pull/33137">extract!</a> returns removed elements
from the array.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 6.0.0.beta2</h4>
<p>Let's pluck all the user emails and then extract emails which include
<code>gmail.com</code>.</p>
<pre><code class="language-ruby">
&gt; &gt; emails = User.pluck(:email)
&gt; &gt; SELECT &quot;users&quot;.&quot;email&quot; FROM &quot;users&quot;

=&gt; [&quot;amit.choudhary@bigbinary.com&quot;, &quot;amit@gmail.com&quot;, &quot;mark@gmail.com&quot;, &quot;sam@gmail.com&quot;]

&gt; &gt; emails.extract! { |email| email.include?('gmail.com') }

=&gt; [&quot;amit@gmail.com&quot;, &quot;mark@gmail.com&quot;, &quot;sam@gmail.com&quot;]

&gt; &gt; emails

=&gt; [&quot;amit.choudhary@bigbinary.com&quot;]

&gt; &gt; emails = User.pluck(:email)
&gt; &gt; SELECT &quot;users&quot;.&quot;email&quot; FROM &quot;users&quot;

=&gt; [&quot;amit.choudhary@bigbinary.com&quot;, &quot;amit@gmail.com&quot;, &quot;mark@gmail.com&quot;, &quot;sam@gmail.com&quot;]

&gt; &gt; emails.reject! { |email| email.include?('gmail.com') }

=&gt; [&quot;amit.choudhary@bigbinary.com&quot;]

&gt; &gt; emails

=&gt; [&quot;amit.choudhary@bigbinary.com&quot;]
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/33137">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds Enumerable#index_with]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-enumerable-index_with"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-enumerable-index_with.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-enumerable-index_with</id>
      <published>2019-06-17T00:00:00.000Z</published>
      <updated>2019-06-17T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-enumerable-index_with.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 added indexwith on Enumerable module. This will help in creating a hash from an enumerator with default or fetched values. Before Rails 6, we can achieve this by calling map along with toh....]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-enumerable-index_with"><![CDATA[<p>Rails 6 added <a href="https://github.com/rails/rails/pull/32523">index_with</a> on
<a href="https://api.rubyonrails.org/v5.2/classes/Enumerable.html">Enumerable</a> module.
This will help in creating a hash from an enumerator with default or fetched
values.</p>
<p>Before Rails 6, we can achieve this by calling
<a href="https://ruby-doc.org/core-2.5.1/Array.html#method-i-map">map</a> along with
<a href="https://ruby-doc.org/core-2.5.1/Array.html#method-i-to_h">to_h</a>.</p>
<p><a href="https://github.com/rails/rails/pull/32523">index_with</a> takes both value or a
block as a parameter.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<p>Let's create a hash from an array in Rails 5.2 using
<a href="https://ruby-doc.org/core-2.5.1/Array.html#method-i-map">map</a> and
<a href="https://ruby-doc.org/core-2.5.1/Array.html#method-i-to_h">to_h</a>.</p>
<pre><code class="language-ruby">
&gt; &gt; address = Address.first
&gt; &gt; SELECT &quot;addresses&quot;.\* FROM &quot;addresses&quot;
&gt; &gt; ORDER BY &quot;addresses&quot;.&quot;id&quot; ASC LIMIT \$1 [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;Address id: 1, first_name: &quot;Amit&quot;, last_name: &quot;Choudhary&quot;, state: &quot;California&quot;, created_at: &quot;2019-03-21 10:03:57&quot;, updated_at: &quot;2019-03-21 10:03:57&quot;&gt;

&gt; &gt; NAME_ATTRIBUTES = [:first_name, :last_name]

=&gt; [:first_name, :last_name]

&gt; &gt; NAME_ATTRIBUTES.map { |attr| [attr, address.public_send(attr)] }.to_h

=&gt; {:first_name=&gt;&quot;Amit&quot;, :last_name=&gt;&quot;Choudhary&quot;}
</code></pre>
<h4>Rails 6.0.0.beta2</h4>
<p>Now let's create the same hash from the array using
<a href="https://github.com/rails/rails/pull/32523">index_with</a> in Rails 6.</p>
<pre><code class="language-ruby">
&gt; &gt; address = Address.first
&gt; &gt; SELECT &quot;addresses&quot;.\* FROM &quot;addresses&quot;
&gt; &gt; ORDER BY &quot;addresses&quot;.&quot;id&quot; ASC LIMIT \$1 [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;Address id: 1, first_name: &quot;Amit&quot;, last_name: &quot;Choudhary&quot;, state: &quot;California&quot;, created_at: &quot;2019-03-21 10:02:47&quot;, updated_at: &quot;2019-03-21 10:02:47&quot;&gt;

&gt; &gt; NAME_ATTRIBUTES = [:first_name, :last_name]

=&gt; [:first_name, :last_name]

&gt; &gt; NAME_ATTRIBUTES.index_with { |attr| address.public_send(attr) }

=&gt; {:first_name=&gt;&quot;Amit&quot;, :last_name=&gt;&quot;Choudhary&quot;}

&gt; &gt; NAME_ATTRIBUTES.index_with('Default')

=&gt; {:first_name=&gt;&quot;Default&quot;, :last_name=&gt;&quot;Default&quot;}
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/32523">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds private option to delegate method]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-private-option-to-delegate-method"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-private-option-to-delegate-method.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-private-option-to-delegate-method</id>
      <published>2019-06-10T00:00:00.000Z</published>
      <updated>2019-06-10T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-private-option-to-delegate-method.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds :private option to delegate method. After this addition, we can delegate methods in the private scope. Let's checkout how it works. Rails 6.0.0.beta2 Let's create two models named as...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-private-option-to-delegate-method"><![CDATA[<p>Rails 6 adds <code>:private</code> option to
<a href="https://api.rubyonrails.org/v5.2/classes/Module.html#method-i-delegate">delegate</a>
method. After this addition, we can delegate methods in the private scope.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 6.0.0.beta2</h4>
<p>Let's create two models named as <code>Address</code> and <code>Order</code>. Let's also delegate
<code>validate_state</code> method in <code>Order</code> to <code>Address</code>.</p>
<pre><code class="language-ruby">class Address &lt; ApplicationRecord
  validates :first_name, :last_name, :state, presence: true

  DELIVERABLE_STATES = ['New York']

  def validate_state
    unless DELIVERABLE_STATES.include?(state)
      errors.add(:state, :invalid)
    end
  end
end

class Order &lt; ApplicationRecord
  belongs_to :address

  delegate :validate_state, to: :address
end

&gt;&gt; Order.first
SELECT &quot;orders&quot;.* FROM &quot;orders&quot;
ORDER BY &quot;orders&quot;.&quot;id&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;Order id: 1, amount: 0.1e2, address_id: 1, created_at: &quot;2019-03-21 10:02:58&quot;, updated_at: &quot;2019-03-21 10:17:44&quot;&gt;

&gt;&gt; Address.first
SELECT &quot;addresses&quot;.* FROM &quot;addresses&quot;
ORDER BY &quot;addresses&quot;.&quot;id&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;Address id: 1, first_name: &quot;Amit&quot;, last_name: &quot;Choudhary&quot;, state: &quot;California&quot;, created_at: &quot;2019-03-21 10:02:47&quot;, updated_at: &quot;2019-03-21 10:02:47&quot;&gt;

&gt;&gt; Order.first.validate_state
SELECT &quot;orders&quot;.* FROM &quot;orders&quot;
ORDER BY &quot;orders&quot;.&quot;id&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

SELECT &quot;addresses&quot;.* FROM &quot;addresses&quot;
WHERE &quot;addresses&quot;.&quot;id&quot; = $1 LIMIT $2  [[&quot;id&quot;, 1], [&quot;LIMIT&quot;, 1]]

=&gt; [&quot;is invalid&quot;]
</code></pre>
<p>Now, let's add <code>private: true</code> to the delegation.</p>
<pre><code class="language-ruby">class Order &lt; ApplicationRecord
  belongs_to :address

  delegate :validate_state, to: :address, private: true
end

&gt;&gt; Order.first.validate_state
SELECT &quot;orders&quot;.* FROM &quot;orders&quot;
ORDER BY &quot;orders&quot;.&quot;id&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; Traceback (most recent call last):
        1: from (irb):7
NoMethodError (private method 'validate_state' called for #&lt;Order:0x00007fb9d72fc1f8&gt;
Did you mean?  validate)
</code></pre>
<p>As we can see, Rails now raises an exception of private method called if
<code>private</code> option is set with <code>delegate</code> method.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/31944">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 allows spaces in postgres table names]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-allows-spaces-in-postgres-table-names"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-allows-spaces-in-postgres-table-names.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-allows-spaces-in-postgres-table-names</id>
      <published>2019-06-05T00:00:00.000Z</published>
      <updated>2019-06-05T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-allows-spaces-in-postgres-table-names.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 allows spaces in tables names in PostgreSQL. Before Rails 6, if we try to create a table named as user reviews, Rails tries to create a table named as reviews in schema named as user. Let's...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-allows-spaces-in-postgres-table-names"><![CDATA[<p>Rails 6 allows spaces in tables names in PostgreSQL. Before Rails 6, if we try
to create a table named as <code>user reviews</code>, Rails tries to create a table named
as <code>reviews</code> in schema named as <code>user</code>.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<p>Let's create a table <code>user reviews</code> in Rails 5.2.</p>
<pre><code class="language-ruby">&gt;&gt; class CreateUserReviews &lt; ActiveRecord::Migration[5.2]
&gt;&gt;   def change
&gt;&gt;     create_table 'user reviews' do |t|
&gt;&gt;       t.string :value
&gt;&gt;
&gt;&gt;       t.timestamps
&gt;&gt;     end
&gt;&gt;   end
&gt;&gt; end

=&gt; :change

&gt;&gt; CreateUserReviews.new.change
-- create_table(&quot;user reviews&quot;)
CREATE TABLE &quot;user&quot;.&quot;reviews&quot; (&quot;id&quot; bigserial primary key, &quot;value&quot; character varying, &quot;created_at&quot; timestamp NOT NULL, &quot;updated_at&quot; timestamp NOT NULL)

=&gt; Traceback (most recent call last):
        2: from (irb):10
        1: from (irb):3:in 'change'
ActiveRecord::StatementInvalid (PG::InvalidSchemaName: ERROR:  schema &quot;user&quot; does not exist)
LINE 1: CREATE TABLE &quot;user&quot;.&quot;reviews&quot; (&quot;id&quot; bigserial primary key, &quot;...
                     ^
: CREATE TABLE &quot;user&quot;.&quot;reviews&quot; (&quot;id&quot; bigserial primary key, &quot;value&quot; character varying, &quot;created_at&quot; timestamp NOT NULL, &quot;updated_at&quot; timestamp NOT NULL)
</code></pre>
<p>We can see that Rails 5.2 raised an exception and tried to create table named as
<code>reviews</code> in <code>user</code> schema.</p>
<h4>Rails 6.0.0.beta2</h4>
<p>Now, let's create a table <code>user reviews</code> in Rails 6.</p>
<pre><code class="language-ruby">&gt;&gt; class CreateUserReviews &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     create_table 'user reviews' do |t|
&gt;&gt;       t.string :value
&gt;&gt;
&gt;&gt;       t.timestamps
&gt;&gt;     end
&gt;&gt;   end
&gt;&gt; end

=&gt; :change

&gt;&gt; CreateUserReviews.new.change
-- create_table(&quot;user reviews&quot;)
CREATE TABLE &quot;user reviews&quot; (&quot;id&quot; bigserial primary key, &quot;value&quot; character varying, &quot;created_at&quot; timestamp(6) NOT NULL, &quot;updated_at&quot; timestamp(6) NOT NULL)

=&gt; #&lt;PG::Result:0x00007f9d633c5458 status=PGRES_COMMAND_OK ntuples=0 nfields=0 cmd_tuples=0&gt;
</code></pre>
<p>Now, we can see that the SQL generated is correct and Rails successfully created
a table named as <code>user reviews</code>.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/34561">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds if_not_exists option to create_table]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-if_not_exists-option-to-create_table"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-if_not_exists-option-to-create_table.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-if_not_exists-option-to-create_table</id>
      <published>2019-05-22T00:00:00.000Z</published>
      <updated>2019-05-22T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-if_not_exists-option-to-create_table.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 added ifnotexists to createtable option to create a table if it doesn't exist. Before Rails 6, we could use ActiveRecord::Base.connection.tableexists?. Default value of ifnotexists option is...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-if_not_exists-option-to-create_table"><![CDATA[<p>Rails 6 added <a href="https://github.com/rails/rails/pull/31382">if_not_exists</a> to
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_table">create_table</a>
option to create a table if it doesn't exist.</p>
<p>Before Rails 6, we could use
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-table_exists-3F">ActiveRecord::Base.connection.table_exists?</a>.</p>
<p>Default value of <a href="https://github.com/rails/rails/pull/31382">if_not_exists</a>
option is <code>false</code>.</p>
<h4>Rails 5.2</h4>
<p>Let's create <code>users</code> table in Rails 5.2.</p>
<pre><code class="language-ruby">&gt;&gt; class CreateUsers &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     create_table :users do |t|
&gt;&gt;       t.string :name, index: { unique: true }
&gt;&gt;
&gt;&gt;       t.timestamps
&gt;&gt;     end
&gt;&gt;   end
&gt;&gt; end

&gt;&gt; CreateUsers.new.change
-- create_table(:users)
CREATE TABLE &quot;users&quot; (&quot;id&quot; bigserial primary key, &quot;name&quot; character varying, &quot;created_at&quot; timestamp NOT NULL, &quot;updated_at&quot; timestamp NOT NULL)

=&gt; #&lt;PG::Result:0x00007fd73e711cf0 status=PGRES_COMMAND_OK ntuples=0 nfields=0 cmd_tuples=0&gt;
</code></pre>
<p>Now let's try creating <code>users</code> table again with
<a href="https://github.com/rails/rails/pull/31382">if_not_exists</a> option.</p>
<pre><code class="language-ruby">&gt;&gt; class CreateUsers &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     create_table :users, if_not_exists: true do |t|
&gt;&gt;       t.string :name, index: { unique: true }
&gt;&gt;
&gt;&gt;       t.timestamps
&gt;&gt;     end
&gt;&gt;   end
&gt;&gt; end

&gt;&gt; CreateUsers.new.change
-- create_table(:users, {:if_not_exists=&gt;true})
CREATE TABLE &quot;users&quot; (&quot;id&quot; bigserial primary key, &quot;name&quot; character varying, &quot;created_at&quot; timestamp NOT NULL, &quot;updated_at&quot; timestamp NOT NULL)

=&gt; Traceback (most recent call last):
        2: from (irb):121
        1: from (irb):114:in 'change'
ActiveRecord::StatementInvalid (PG::DuplicateTable: ERROR:  relation &quot;users&quot; already exists)
: CREATE TABLE &quot;users&quot; (&quot;id&quot; bigserial primary key, &quot;name&quot; character varying, &quot;created_at&quot; timestamp NOT NULL, &quot;updated_at&quot; timestamp NOT NULL)
</code></pre>
<p>We can see that Rails 5.2 ignored
<a href="https://github.com/rails/rails/pull/31382">if_not_exists</a> option and tried
creating the table again.</p>
<p>Now let's try
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-table_exists-3F">ActiveRecord::Base.connection.table_exists?</a>
with Rails 5.2.</p>
<pre><code class="language-ruby">&gt;&gt; class CreateUsers &lt; ActiveRecord::Migration[5.2]
&gt;&gt;   def change
&gt;&gt;     unless ActiveRecord::Base.connection.table_exists?('users')
&gt;&gt;       create_table :users do |t|
&gt;&gt;         t.string :name
&gt;&gt;
&gt;&gt;         t.timestamps
&gt;&gt;       end
&gt;&gt;     end
&gt;&gt;   end
&gt;&gt; end

&gt;&gt; CreateUsers.new.change

=&gt; nil
</code></pre>
<p>We can see that <code>create_table :users</code> never executed because
<code>ActiveRecord::Base.connection.table_exists?('users')</code> returned true.</p>
<h4>Rails 6.0.0.beta2</h4>
<p>Let's create <code>users</code> table in Rails 6 with
<a href="https://github.com/rails/rails/pull/31382">if_not_exists</a> option set as true.</p>
<pre><code class="language-ruby">&gt;&gt; class CreateUsers &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     create_table :users, if_not_exists: true do |t|
&gt;&gt;       t.string :name, index: { unique: true }
&gt;&gt;
&gt;&gt;       t.timestamps
&gt;&gt;     end
&gt;&gt;   end
&gt;&gt; end

&gt;&gt; CreateUsers.new.change
-- create_table(:users, {:if_not_exists=&gt;true})
CREATE TABLE IF NOT EXISTS &quot;users&quot; (&quot;id&quot; bigserial primary key, &quot;name&quot; character varying, &quot;created_at&quot; timestamp(6) NOT NULL, &quot;updated_at&quot; timestamp(6) NOT NULL)

=&gt; #&lt;PG::Result:0x00007fc4614fef48 status=PGRES_COMMAND_OK ntuples=0 nfields=0 cmd_tuples=0&gt;

&gt;&gt; CreateUsers.new.change
-- create_table(:users, {:if_not_exists=&gt;true})
CREATE TABLE IF NOT EXISTS &quot;users&quot; (&quot;id&quot; bigserial primary key, &quot;name&quot; character varying, &quot;created_at&quot; timestamp(6) NOT NULL, &quot;updated_at&quot; timestamp(6) NOT NULL)

=&gt; #&lt;PG::Result:0x00007fc46513fde0 status=PGRES_COMMAND_OK ntuples=0 nfields=0 cmd_tuples=0&gt;
</code></pre>
<p>We can see that no exception was raised when we tried creating <code>users</code> table the
second time.</p>
<p>Now let's see what happens if we set
<a href="https://github.com/rails/rails/pull/31382">if_not_exists</a> to false.</p>
<pre><code class="language-ruby">&gt;&gt; class CreateUsers &lt; ActiveRecord::Migration[6.0]
&gt;&gt;   def change
&gt;&gt;     create_table :users, if_not_exists: false do |t|
&gt;&gt;       t.string :name, index: { unique: true }
&gt;&gt;
&gt;&gt;       t.timestamps
&gt;&gt;     end
&gt;&gt;   end
&gt;&gt; end

&gt;&gt; CreateUsers.new.change
-- create_table(:users, {:if_not_exists=&gt;false})
CREATE TABLE &quot;users&quot; (&quot;id&quot; bigserial primary key, &quot;name&quot; character varying, &quot;created_at&quot; timestamp(6) NOT NULL, &quot;updated_at&quot; timestamp(6) NOT NULL)

=&gt; Traceback (most recent call last):
        2: from (irb):23
        1: from (irb):15:in `change'
ActiveRecord::StatementInvalid (PG::DuplicateTable: ERROR:  relation &quot;users&quot; already exists
)
</code></pre>
<p>As we can see, Rails raised an exception here because
<a href="https://github.com/rails/rails/pull/31382">if_not_exists</a> was set to false.</p>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/31382">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 has added a way to change the database of the app]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-has-added-a-way-to-change-the-database-of-the-app"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-has-added-a-way-to-change-the-database-of-the-app.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-has-added-a-way-to-change-the-database-of-the-app</id>
      <published>2019-04-30T00:00:00.000Z</published>
      <updated>2019-04-30T00:00:00.000Z</updated>
      <author>
        <name>Prathamesh Sonpatki</name>
        <uri>https://www.bigbinary.com/blog/authors/prathamesh</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-has-added-a-way-to-change-the-database-of-the-app.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[It is possible to change the database configuration using a simple command]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-has-added-a-way-to-change-the-database-of-the-app"><![CDATA[<p>Rails allows us to use different databases using the <code>database.yml</code> config file.
It uses sqlite3 as the default database when a new Rails app is created. But it
is also possible to use different databases such as MySQL or PostgreSQL. The
contents of <code>database.yml</code> change as per the database. Also each database has a
different adapter. We need to include the gems <code>pg</code> or <code>mysql2</code> accordingly.</p>
<p>Before Rails 6, it was not possible to change the contents of <code>database.yml</code>
automatically. But now a
<a href="https://github.com/rails/rails/pull/34832">command has been added</a> to do this
automatically.</p>
<p>Let's say our app has started with sqlite and now we have to switch to MySQL.</p>
<pre><code class="language-bash">$ rails db:system:change --to=mysql
    conflict  config/database.yml
Overwrite /Users/prathamesh/Projects/reproductions/squish_app/config/database.yml? (enter &quot;h&quot; for help) [Ynaqdhm] Y
       force  config/database.yml
        gsub  Gemfile
        gsub  Gemfile
</code></pre>
<p>Our <code>database.yml</code> is now changed to contain the configuration for MySQL
database and the <code>Gemfile</code> also gets updated automatically with addition of
<code>mysql2</code> gem in place of <code>sqlite3</code>.</p>
<p>This command also takes care of using
<a href="https://github.com/rails/rails/pull/35522">proper gem versions</a> in the Gemfile
when the database backend is changed.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds parallel testing]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-parallel-testing"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-parallel-testing.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-parallel-testing</id>
      <published>2019-04-29T00:00:00.000Z</published>
      <updated>2019-04-29T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-parallel-testing.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[We frequently think about how good it would be if we could run tests in parallel on local so there would be less wait time for tests to be completed. Wait times increase considerably when the count...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-parallel-testing"><![CDATA[<p>We frequently think about how good it would be if we could run tests in parallel
on local so there would be less wait time for tests to be completed. Wait times
increase considerably when the count of tests are on the higher side, which is a
common case for a lot of applications.</p>
<p>Though CI tools like <a href="https://circleci.com/">CircleCi</a> and
<a href="https://travis-ci.org/">Travis CI</a> provide a feature to run tests in parallel,
there still wasn't a straightforward way to parallelize tests on local before
Rails 6.</p>
<p>Before Rails 6, if we wanted to parallelize tests, we would use
<a href="https://github.com/grosser/parallel_tests">Parallel Tests</a>.</p>
<p>Rails 6 adds the parallelization of tests by default. Rails 6 added
<a href="https://github.com/rails/rails/pull/31900">parallelize</a> as a class method on
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveSupport/TestCase.html">ActiveSupport::TestCase</a>
which takes a hash as a parameter with the keys <code>workers</code> and <code>with</code>. The
<code>worker</code> key is responsible for setting the number of parallel workers. The
default value of the <code>worker</code> key is <code>:number_of_processors</code>, which finds the
number of processors on the machine and sets it as the number of parallel
workers. <code>with</code> takes two values - <code>:processes</code>, which is the default one, and
<code>:threads</code> as a value.</p>
<p>Rails 6 also added two hooks - <code>parallelize_setup</code>, which is called before the
processes are forked, and <code>parallelize_teardown</code>, which is called after the
processes are killed. Rails 6 also handles creation of multiple databases and
namespacing of those databases for parallel tests out of the box.</p>
<p>If we want to disable parallel testing, we can set the value of <code>workers</code> as 1
or less.</p>
<h4>Rails 6.0.0.beta2</h4>
<pre><code class="language-ruby">class ActiveSupport::TestCase
  parallelize_setup do |worker|
    # setup databases
  end
   parallelize_teardown do |worker|
    # cleanup database
  end

  # Run tests in parallel with specified workers
  parallelize(workers: :number_of_processors)

  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  fixtures :all

  # Add more helper methods to be used by all tests here...
end
</code></pre>
<p>Rails 6 also provides an environment variable <code>PARALLEL_WORKERS</code> to set the
number of parallel workers on runtime.</p>
<pre><code class="language-bash">$ PARALLEL_WORKERS=10 bin/rails test
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/31900">pull request</a>
for adding <code>parallelize</code> and
<a href="https://github.com/rails/rails/pull/34735">pull request</a> for setting number of
processors as default workers count.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 improves ActiveSupport::Notifications::Event]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-cpu-time-idle-time-and-allocations-to-activesupport-notifications-event"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-cpu-time-idle-time-and-allocations-to-activesupport-notifications-event.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-cpu-time-idle-time-and-allocations-to-activesupport-notifications-event</id>
      <published>2019-04-24T00:00:00.000Z</published>
      <updated>2019-04-24T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-cpu-time-idle-time-and-allocations-to-activesupport-notifications-event.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds CPU time, idle time and allocations to ActiveSupport::Notifications::Event]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-cpu-time-idle-time-and-allocations-to-activesupport-notifications-event"><![CDATA[<p>Rails provides an easy way to instrument events and ability to subscribe to
those events using
<a href="https://guides.rubyonrails.org/active_support_instrumentation.html">Active Support Instrumentation</a>
API.</p>
<h2>Before Rails 6</h2>
<p>Before Rails 6, the subscriber of an event can access the event's start time,
end time and the duration along with the other event information.</p>
<p>To demonstrate how to access this information from an event, we will instrument
a custom event <code>custom_sleep_event</code> and attach a subscriber to that event.</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe('custom_sleep_event') do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  puts &quot;Event: #{event.inspect}&quot;
  puts &quot;Started: #{event.time}&quot;
  puts &quot;Finished: #{event.end}&quot;
  puts &quot;Duration (ms): #{event.duration}&quot;
end

ActiveSupport::Notifications.instrument('custom_sleep_event') do
  sleep 2
end
</code></pre>
<p>The event subscriber should print something similar.</p>
<pre><code class="language-plaintext">Event: #&lt;ActiveSupport::Notifications::Event:0x00007f952fc6a0b8 @name=&quot;custom_sleep_event&quot;, @payload={}, @time=2019-04-11 16:58:52 +0530, @transaction_id=&quot;e82231ab65b7af3c85ec&quot;, @end=2019-04-11 16:58:54 +0530, @children=[], @duration=nil&gt;

Started: 2019-04-11 16:58:52 +0530

Finished: 2019-04-11 16:58:54 +0530

Duration (ms): 2001.287
</code></pre>
<h2>Improvements and additions made to ActiveSupport::Notifications::Event in Rails 6</h2>
<p>Rails 6 has improved the way an event's duration is computed and also added
useful information accessible on an event object such as CPU time, idle time and
allocations.</p>
<p>Let's discuss it in more detail.</p>
<h5>1. <code>CLOCK_MONOTONIC</code> instead of <code>CLOCK_REALTIME</code></h5>
<p>Before Rails 6, <code>Time.now</code> is used for recording the event's start time and end
time. To avoid
<a href="https://github.com/rails/rails/issues/34271">issues with the machine changing time</a>,
Rails 6 now uses
<a href="https://www.rubydoc.info/gems/concurrent-ruby/Concurrent.monotonic_time"><code>Concurrent.monotonic_time</code></a>
instead of <code>Time.now</code> to record the event's both start time and end time
accurately.</p>
<p>Initially
<a href="https://ruby-doc.org/core-2.5.3/Process.html#method-c-clock_gettime"><code>Process.clock_gettime(Process::CLOCK_MONOTONIC)</code></a>
was used which
<a href="https://github.com/rails/rails/commit/dda9452314bb904a3e2c850bd23f118eb80e3356#diff-b82336d1f77b84d28210f9b46fcff97d">later modified</a>
to use <code>Concurrent.monotonic_time</code>. Note that <code>Concurrent.monotonic_time</code> is
same but returns more precise time than
<code>Process.clock_gettime(Process::CLOCK_MONOTONIC)</code>.</p>
<blockquote>
<p><code>Time.now</code> or <code>Process.clock_gettime(Process::CLOCK_REALTIME)</code> can jump
forwards and backwards as the system time-of-day clock is changed. Whereas,
clock time using <code>CLOCK_MONOTONIC</code> returns the absolute wall-clock time since
an unspecified time in the past (for example, system start-up time, or the
Epoch). The <code>CLOCK_MONOTONIC</code> does not change with the system time-of-day
clock, it just keeps advances forwards at one tick per tick and resets if the
system is rebooted. In general, <code>CLOCK_MONOTONIC</code> is recommended to compute
the elapsed time between two events. To read more about the differences
between <code>CLOCK_REALTIME</code> and <code>CLOCK_MONOTONIC</code>, please check the discussion on
[this Stackoverflow thread](https://stackoverflow.com/questions/3523442/&gt;
difference-between-clock-realtime-and-clock-monotonic). Another
<a href="https://blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way/">article</a>
written by Luca Guidi on the same topic is a recommended read.</p>
</blockquote>
<h5>2. No need to create hand made event objects on our own</h5>
<p>Since it is a common practice to initialize an event using
<code>ActiveSupport::Notifications::Event.new(*args)</code> in the event subscriber block,
<a href="https://github.com/rails/rails/pull/33451">Rails 6 now makes this a bit easy</a>.
If the block passed to the subscriber only takes one argument then the Active
Support Notification framework now yields an event object to the block.</p>
<p>Therefore, the subscriber definition below</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe('an_event') do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  puts &quot;Event #{event.name} received.&quot;
end
</code></pre>
<p>now can be simplified in Rails 6 as follows.</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe('an_event') do |event|
  puts &quot;Event #{event.name} received.&quot;
end
</code></pre>
<h5>3. CPU time and idle time</h5>
<p>Rails 6 now computes elapsed CPU time of an event with the help of
<a href="https://ruby-doc.org/core-2.5.3/Process.html#method-c-clock_gettime"><code>Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID)</code></a>.</p>
<p>System (kernel) keeps track of CPU time per process. The clock time returned
using <code>CLOCK_PROCESS_CPUTIME_ID</code> represents the CPU time that has passed since
the process started. Since a process may not always get all CPU cycles between
start and finish of the process, the process often has to (sleep and) share CPU
time among other processes. If the system puts a process to sleep, then the time
spend waiting is not counted in the process' CPU time.</p>
<p>The CPU time of an event can be fetched using the <code>#cpu_time</code> method.</p>
<p>Also, Rails 6 now computes the idle time of an event, too. The idle time of an
event represents the difference between the event's <code>#duration</code> and <code>#cpu_time</code>.
Note that the <code>#duration</code> is computed using the difference between the event's
monotonic time at the start (<code>#time</code>) and the monotonic time at the end
(<code>#end</code>).</p>
<p>Let's see how to get these time values.</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe('custom_sleep_event') do |event|
  puts &quot;Event: #{event.inspect}&quot;
  puts &quot;Started: #{event.time}&quot;
  puts &quot;Finished: #{event.end}&quot;
  puts &quot;Duration (ms): #{event.duration}&quot;
  puts &quot;CPU time (ms): #{event.cpu_time}&quot;
  puts &quot;Idle time (ms): #{event.idle_time}&quot;
end

ActiveSupport::Notifications.instrument('custom_sleep_event') do
  sleep 2
end
</code></pre>
<p>It prints this.</p>
<pre><code class="language-plaintext">Event: #&lt;ActiveSupport::Notifications::Event:0x00007fb02ac72400 @name=&quot;custom_sleep_event&quot;, @payload={}, @time=29514.525707, @transaction_id=&quot;43ca8e1c378b6b00d861&quot;, @end=29516.528971, @children=[], @duration=nil, @cpu_time_start=2.238801, @cpu_time_finish=2.238874, @allocation_count_start=835821, @allocation_count_finish=835821&gt;

Started: 29514.525707

Finished: 29516.528971

Duration (ms): 2003.2639999990351

CPU time (ms): 0.07299999999998974

Idle time (ms): 2003.190999999035
</code></pre>
<p>Notice the <code>@cpu_time_start</code> and <code>@cpu_time_finish</code> counters in the inspected
event object representation which are used to calculate the CPU time.</p>
<h5>4. Allocations</h5>
<p>We will now know how many objects were allocated between the start and end of an
event using event's <code>#allocations</code> method.</p>
<pre><code class="language-ruby">ActiveSupport::Notifications.subscribe('custom_sleep_event') do |event|
  puts &quot;Event: #{event.inspect}&quot;
  puts &quot;Started: #{event.time}&quot;
  puts &quot;Finished: #{event.end}&quot;
  puts &quot;Duration (ms): #{event.duration}&quot;
  puts &quot;CPU time (ms): #{event.cpu_time}&quot;
  puts &quot;Idle time (ms): #{event.idle_time}&quot;
  puts &quot;# of objects allocated: #{event.allocations}&quot;
end

ActiveSupport::Notifications.instrument('custom_sleep_event') do
  sleep 2
end
</code></pre>
<p>The above example should print something like this.</p>
<pre><code class="language-plaintext">Event: #&lt;ActiveSupport::Notifications::Event:0x00007fed8c4e33c0 @name=&quot;custom_sleep_event&quot;, @payload={}, @time=30503.508897, @transaction_id=&quot;5330165dae2b49fbe143&quot;, @end=30505.513547, @children=[], @duration=nil, @cpu_time_start=2.813231, @cpu_time_finish=2.813404, @allocation_count_start=834227, @allocation_count_finish=834228&gt;

Started: 30503.508897

Finished: 30505.513547

Duration (ms): 2004.6499999989464

CPU time (ms): 0.17299999999975668

Idle time (ms): 2004.4769999989467

# of objects allocated: 1
</code></pre>
<p>Notice the <code>@allocation_count_finish</code> and <code>@allocation_count_start</code> counters in
the inspected event object representation which are used to calculate the number
of objects allocated during an event whose difference is (834228 - 834227 = 1).</p>
<blockquote>
<p>In case of JRuby, the
<a href="https://github.com/rails/rails/blob/3e628c48406440811f9201e2db7ba0df53bb38e1/activesupport/lib/active_support/notifications/instrumenter.rb#L155-L157">allocations would be zero</a>.</p>
</blockquote>
<h5>5. <code>#start!</code> and <code>#finish!</code></h5>
<p>Two public methods <code>#start!</code> and <code>#finish!</code> have been introduced to
<code>ActiveSupport::Notifications::Event</code> which can be used to record more
information.</p>
<p>The <code>#start!</code> method
<a href="https://github.com/rails/rails/blob/45511fa8b20c621e2cf193ddaeb7d6fbe8432fea/activesupport/lib/active_support/notifications/instrumenter.rb#L79-L83">resets</a>
the <code>@time</code>, <code>@cpu_time_start</code> and <code>@allocation_count_start</code> counters.
Similarly, the <code>#finish!</code> method also
<a href="https://github.com/rails/rails/blob/45511fa8b20c621e2cf193ddaeb7d6fbe8432fea/activesupport/lib/active_support/notifications/instrumenter.rb#L86-L90">resets</a>
the <code>@end</code>, <code>@cpu_time_finish</code> and <code>@allocation_count_finish</code> counters.</p>
<hr>
<p>To learn more about this feature, please check
<a href="https://github.com/rails/rails/pull/33449">rails/rails#33449</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 allows configuring has_secure_password attribute]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-allows-configurable-attribute-name-on-has_secure_password"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-allows-configurable-attribute-name-on-has_secure_password.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-allows-configurable-attribute-name-on-has_secure_password</id>
      <published>2019-04-23T00:00:00.000Z</published>
      <updated>2019-04-23T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-allows-configurable-attribute-name-on-has_secure_password.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 allows configurable attribute name on has_secure_password]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-allows-configurable-attribute-name-on-has_secure_password"><![CDATA[<p><a href="https://api.rubyonrails.org/v5.2/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password">has_secure_password</a>
is used to encrypt and authenticate passwords using
<a href="https://github.com/codahale/bcrypt-ruby">BCrypt</a> . It assumes the model has a
column named <code>password_digest</code>.</p>
<p>Before Rails 6,
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password">has_secure_password</a>
did not accept any attribute as a parameter. So, if we needed
<a href="https://github.com/codahale/bcrypt-ruby">BCrypt</a> encryption on a different
column other than <code>password_digest</code>, we would have to manually encrypt the value
before storing it.</p>
<p>Rails 6 makes it easy and allows custom attributes as a parameter to
<code>has_secure_password</code>. <code>has_secure_password</code> still defaults to <code>password</code> so it
works with previous versions of Rails. <code>has_secure_password</code> still needs the
column named <code>column_name_digest</code> defined on the model.</p>
<p><code>has_secure_password</code> also adds the <code>authenticate_column_name</code> method to
authenticate the custom column.</p>
<p>Let's check out how it works.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   has_secure_password
&gt;&gt; end

=&gt; [ActiveModel::Validations::ConfirmationValidator]

&gt;&gt; user = User.create(email: 'amit.choudhary@bigbinary.com', password: 'amit.choudhary')
BEGIN
User Create (0.8ms)  INSERT INTO &quot;users&quot; (&quot;email&quot;, &quot;password_digest&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES ($1, $2, $3, $4) RETURNING &quot;id&quot;  [[&quot;email&quot;, &quot;amit.choudhary@bigbinary.com&quot;], [&quot;password_digest&quot;, &quot;$2a$10$g6ZJNgakn4I1w/qjAx3vM.I76QSNjFCHtTtT9ovko/9Th50SEmIBO&quot;], [&quot;created_at&quot;, &quot;2019-03-17 23:30:13.754379&quot;], [&quot;updated_at&quot;, &quot;2019-03-17 23:30:13.754379&quot;]]
COMMIT

=&gt; #&lt;User id: 1, email: &quot;amit.choudhary@bigbinary.com&quot;, password_digest: &quot;$2a$10$g6ZJNgakn4I1w/qjAx3vM.I76QSNjFCHtTtT9ovko/9...&quot;, created_at: &quot;2019-03-17 23:30:13&quot;, updated_at: &quot;2019-03-17 23:30:13&quot;&gt;

&gt;&gt; user.authenticate('amit.choudhary')

=&gt; #&lt;User id: 1, email: &quot;amit.choudhary@bigbinary.com&quot;, password_digest: &quot;$2a$10$g6ZJNgakn4I1w/qjAx3vM.I76QSNjFCHtTtT9ovko/9...&quot;, created_at: &quot;2019-03-17 23:30:13&quot;, updated_at: &quot;2019-03-17 23:30:13&quot;&gt;

&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   has_secure_password :transaction_password
&gt;&gt; end

=&gt; NoMethodError: undefined method 'fetch' for :transaction_password:Symbol
	from (irb):9:in '&lt;class:User&gt;'
	from (irb):8
</code></pre>
<h4>Rails 6.0.0.beta2</h4>
<pre><code class="language-ruby">&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   has_secure_password
&gt;&gt;   has_secure_password :transaction_password
&gt;&gt; end

=&gt; [ActiveModel::Validations::ConfirmationValidator]

&gt;&gt; user = User.create(email: 'amit.choudhary@bigbinary.com', password: 'amit.choudhary', transaction_password: 'amit.choudhary')
BEGIN
User Create (0.5ms)  INSERT INTO &quot;users&quot; (&quot;email&quot;, &quot;password_digest&quot;, &quot;transaction_password_digest&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES ($1, $2, $3, $4, $5) RETURNING &quot;id&quot;  [[&quot;email&quot;, &quot;amit.choudhary@bigbinary.com&quot;], [&quot;password_digest&quot;, &quot;$2a$10$nUiO7E2XrIJx/sSdpG0JAOL00uFvPRH7kXHLk5f/6qA1zLPHIrpPy&quot;], [&quot;transaction_password_digest&quot;, &quot;$2a$10$l6cTpHwV9xOEn2.OumI29OnualGpvr1CgrNrbuMuHyGTltko8eBG2&quot;], [&quot;created_at&quot;, &quot;2019-03-17 23:42:28.723431&quot;], [&quot;updated_at&quot;, &quot;2019-03-17 23:42:28.723431&quot;]]
COMMIT

=&gt; #&lt;User id: 5, email: &quot;amit.choudhary@bigbinary.com&quot;, password_digest: [FILTERED], transaction_password_digest: [FILTERED], created_at: &quot;2019-03-17 23:42:28&quot;, updated_at: &quot;2019-03-17 23:42:28&quot;&gt;

&gt;&gt; user.authenticate('amit.choudhary')

=&gt; #&lt;User id: 5, email: &quot;amit.choudhary@bigbinary.com&quot;, password_digest: [FILTERED], transaction_password_digest: [FILTERED], created_at: &quot;2019-03-17 23:42:28&quot;, updated_at: &quot;2019-03-17 23:42:28&quot;&gt;

&gt;&gt; user.authenticate_transaction_password('amit.choudhary')

=&gt; #&lt;User id: 5, email: &quot;amit.choudhary@bigbinary.com&quot;, password_digest: [FILTERED], transaction_password_digest: [FILTERED], created_at: &quot;2019-03-17 23:42:28&quot;, updated_at: &quot;2019-03-17 23:42:28&quot;&gt;
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/26764">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 allows overriding ActiveModel::Errors#full_message]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-allows-to-override-the-activemodel-errors-full_message-format-at-the-model-level-and-at-the-attribute-level"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-allows-to-override-the-activemodel-errors-full_message-format-at-the-model-level-and-at-the-attribute-level.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-allows-to-override-the-activemodel-errors-full_message-format-at-the-model-level-and-at-the-attribute-level</id>
      <published>2019-04-22T00:00:00.000Z</published>
      <updated>2019-04-22T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-allows-to-override-the-activemodel-errors-full_message-format-at-the-model-level-and-at-the-attribute-level.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 allows to override the ActiveModel::Errors#full_message format at the model level and at the attribute level]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-allows-to-override-the-activemodel-errors-full_message-format-at-the-model-level-and-at-the-attribute-level"><![CDATA[<h2>Before Rails 6</h2>
<p>Before Rails 6, the default format <code>%{attribute} %{message}</code> is used to display
validation error message for a model's attribute.</p>
<pre><code class="language-ruby">
&gt; &gt; article = Article.new
&gt; &gt; =&gt; #&lt;Article id: nil, title: nil, description: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; article.errors.full_message(:title, &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;Title cannot be blank&quot;
&gt; &gt;
</code></pre>
<p>The default format can be overridden globally using a language-specific locale
file.</p>
<pre><code class="language-yaml">
# config/locales/en.yml

en:
errors:
format:
&quot;'%{attribute}' %{message}&quot;
</code></pre>
<p>With this change, the full error message is changed for all the attributes of
all models.</p>
<pre><code class="language-ruby">
&gt; &gt; article = Article.new
&gt; &gt; =&gt; #&lt;Article id: nil, title: nil, description: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; article.errors.full_message(:title, &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;'Title' cannot be blank&quot;

&gt; &gt; user = User.new
&gt; &gt; =&gt; #&lt;User id: nil, first_name: nil, last_name: nil, country: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; user.errors.full_message(:first_name, &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;'First name' cannot be blank&quot;
&gt; &gt;
</code></pre>
<p>This trick works in some cases but it doesn't work if we have to customize the
error messages on the basis of specific models or attributes.</p>
<p>Before Rails 6, there is no easy way to generate error messages like shown
below.</p>
<pre><code class="language-plaintext">The article's title cannot be empty
</code></pre>
<p>or</p>
<pre><code class="language-plaintext">First name of a person cannot be blank
</code></pre>
<p>If we change the <code>errors.format</code> to <code>The article's %{attribute} %{message}</code> in
<code>config/locales/en.yml</code> then that format will be unexpectedly used for other
models, too.</p>
<pre><code class="language-yaml">
# config/locales/en.yml

en:
errors:
format:
&quot;The article's %{attribute} %{message}&quot;
</code></pre>
<p>This is what will happen if we make such a change.</p>
<pre><code class="language-ruby">
&gt; &gt; article = Article.new
&gt; &gt; =&gt; #&lt;Article id: nil, title: nil, description: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; article.errors.full_message(:title, &quot;cannot be empty&quot;)
&gt; &gt; =&gt; &quot;The article's Title cannot be empty&quot;

&gt; &gt; user = User.new
&gt; &gt; =&gt; #&lt;User id: nil, first_name: nil, last_name: nil, country: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; user.errors.full_message(:first_name, &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;The article's First name cannot be blank&quot;
&gt; &gt;
</code></pre>
<p>Notice the error message generated for the <code>:first_name</code> attribute of User
model. This does not look the way we want, right?</p>
<p>Let's see what is changed in Rails 6 to overcome this problem.</p>
<h2>Enhancements made to <code>ActiveModel::Errors#full_message</code> in Rails 6</h2>
<p>Overriding the format of error message globally using <code>errors.format</code> is still
supported in Rails 6.</p>
<p>In addition to that, Rails 6 now also supports overriding the error message's
format at the model level and at the attribute level.</p>
<p>In order to enable this support, we need to explicitly set
<code>config.active_model.i18n_customize_full_message</code> to <code>true</code> in the Rails
configuration file, preferably in <code>config/application.rb</code> which is implicitly
set to <code>false</code> by default.</p>
<h5>Overriding model level format</h5>
<p>We can customize the full error message format for each model separately.</p>
<pre><code class="language-yaml">
# config/locales/en.yml

en:
activerecord:
errors:
models:
article:
format: &quot;`%{attribute}`: %{message}&quot;
user:
format: &quot;%{attribute} of the user %{message}&quot;
</code></pre>
<p>The full error messages will look like this.</p>
<pre><code class="language-ruby">
&gt; &gt; article = Article.new
&gt; &gt; =&gt; #&lt;Article id: nil, title: nil, description: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; article.errors.full_message(:title, &quot;cannot be empty&quot;)
&gt; &gt; =&gt; &quot;`Title`: cannot be empty&quot;
&gt; &gt; article.valid?
&gt; &gt; =&gt; false
&gt; &gt; article.errors.full_messages
&gt; &gt; =&gt; [&quot;`Title`: can't be blank&quot;]

&gt; &gt; user = User.new
&gt; &gt; =&gt; #&lt;User id: nil, first_name: nil, last_name: nil, country: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; user.errors.full_message(:first_name, &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;First name of the user cannot be blank&quot;

&gt; &gt; comment = Comment.new
&gt; &gt; =&gt; #&lt;Comment id: nil, message: nil, author_id: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; comment.errors.full_message(:message, &quot;is required&quot;)
&gt; &gt; =&gt; &quot;Message is required&quot;
&gt; &gt;
</code></pre>
<p>Notice how the default format <code>%{attribute} %{message}</code> is used for generating
the full error messages for the <code>Comment</code> model since its format is not being
overridden.</p>
<p>Since the other methods such as <code>ActiveModel::Errors#full_messages</code>,
<code>ActiveModel::Errors#full_messages_for</code>, <code>ActiveModel::Errors#to_hash</code> etc. use
the <code>ActiveModel::Errors#full_message</code> method under the hood, we get the full
error messages according to the custom format in the returned values of these
methods respectively as expected.</p>
<h5>Overriding attribute level format</h5>
<p>Similar to customizing format at the model level, we can customize the error
format for specific attributes of individual models.</p>
<pre><code class="language-yaml">
# config/locales/en.yml

en:
activerecord:
errors:
models:
article:
attributes:
title:
format: &quot;The article's title %{message}&quot;
user:
attributes:
first_name:
format: &quot;%{attribute} of a person %{message}&quot;
</code></pre>
<p>With such a configuration, we get the customized error message for the <code>title</code>
attribute of the Article model.</p>
<pre><code class="language-ruby">
&gt; &gt; article = Article.new
&gt; &gt; =&gt; #&lt;Article id: nil, title: nil, description: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; article.errors.full_message(:title, &quot;cannot be empty&quot;)
&gt; &gt; =&gt; &quot;The article's title cannot be empty&quot;
&gt; &gt; article.errors.full_message(:description, &quot;cannot be empty&quot;)
&gt; &gt; =&gt; &quot;Description cannot be empty&quot;

&gt; &gt; user = User.new
&gt; &gt; =&gt; #&lt;User id: nil, first_name: nil, last_name: nil, country: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; user.errors.full_message(:first_name, &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;First name of a person cannot be blank&quot;
&gt; &gt; user.errors.full_message(:last_name, &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;Last name cannot be blank&quot;
&gt; &gt;
</code></pre>
<p>Note that the error messages for the rest of the attributes were generated using
the default <code>%{attribute} %{message}</code> format for which we didn't add custom
formats in the <code>config/locales/en.yml</code> manifest.</p>
<h5>Overriding model level format of deeply nested models</h5>
<pre><code class="language-yaml"># config/locales/en.yml

en:
activerecord:
errors:
models:
article/comments/attachments:
format: &quot;%{message}&quot;
</code></pre>
<pre><code class="language-ruby">
&gt; &gt; article = Article.new
&gt; &gt; =&gt; #&lt;Article id: nil, title: nil, description: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; article.errors.full_message(:'comments/attachments.file_name', &quot;is required&quot;)
&gt; &gt; =&gt; &quot;is required&quot;
&gt; &gt; article.errors.full_message(:'comments/attachments.path', &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;cannot be blank&quot;
&gt; &gt; article.errors.full_message(:'comments.message', &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;Comments message cannot be blank&quot;
&gt; &gt;
</code></pre>
<h5>Overriding attribute level format of deeply nested models</h5>
<pre><code class="language-yaml"># config/locales/en.yml

en:
activerecord:
errors:
models:
article/comments/attachments:
attributes:
file_name:
format: &quot;File name of an attachment %{message}&quot;
</code></pre>
<pre><code class="language-ruby">
&gt; &gt; article = Article.new
&gt; &gt; =&gt; #&lt;Article id: nil, title: nil, description: nil, created_at: nil, updated_at: nil&gt;
&gt; &gt; article.errors.full_message(:'comments/attachments.file_name', &quot;is required&quot;)
&gt; &gt; =&gt; &quot;File name of an attachment is required&quot;
&gt; &gt; article.errors.full_message(:'comments/attachments.path', &quot;cannot be blank&quot;)
&gt; &gt; =&gt; &quot;Comments/attachments path cannot be blank&quot;
&gt; &gt;
</code></pre>
<h2>Precedence</h2>
<p>The custom formats specified in the locale file has the following precedence in
the high to low order.</p>
<ul>
<li><code>activerecord.errors.models.article/comments/attachments.attributes.file_name.format</code></li>
<li><code>activerecord.errors.models.article/comments/attachments.format</code></li>
<li><code>activerecord.errors.models.article.attributes.title.format</code></li>
<li><code>activerecord.errors.models.article.format</code></li>
<li><code>errors.format</code></li>
</ul>
<hr>
<p>To learn more, please checkout
<a href="https://github.com/rails/rails/pull/32956">rails/rails#32956</a> and
<a href="https://github.com/rails/rails/pull/35789">rails/rails#35789</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActiveRecord::Relation#extract_associated]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-activerecord-relation-extract_associated"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activerecord-relation-extract_associated.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-activerecord-relation-extract_associated</id>
      <published>2019-04-17T00:00:00.000Z</published>
      <updated>2019-04-17T00:00:00.000Z</updated>
      <author>
        <name>Taha Husain</name>
        <uri>https://www.bigbinary.com/blog/authors/taha</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activerecord-relation-extract_associated.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 added ActiveRecord::Relation#extract_associated for extracting associated records from a relation]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-activerecord-relation-extract_associated"><![CDATA[<p>Before Rails 6, if we want to extract associated records from an
<code>ActiveRecord::Relation</code>, we would use <code>preload</code> and <code>collect</code>.</p>
<p>For example, we want to fetch <code>subscriptions</code> of some <code>users</code>. The query would
look as shown below.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">User.where(blocked: false).preload(:subscriptions).collect(&amp;:subscriptions)

=&gt; # returns collection of subscription records
</code></pre>
<p><a href="https://github.com/rails/rails/pull/35784">ActiveRecord::Relation#extract_associated</a>
provides a shorthand to achieve same result and is more readable than former.</p>
<h4>Rails 6.0.0.beta3</h4>
<pre><code class="language-ruby">User.where(blocked: false).extract_associated(:subscriptions)

=&gt; # returns the same collection of subscription records
</code></pre>
<p>Here's the relevant <a href="https://github.com/rails/rails/pull/35784">pull request</a>
for this change.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds implicit_order_column]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-implicit_order_column"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-implicit_order_column.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-implicit_order_column</id>
      <published>2019-04-16T00:00:00.000Z</published>
      <updated>2019-04-16T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-implicit_order_column.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds implicit_order_column for ordering records implicitly]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-implicit_order_column"><![CDATA[<p>Rails 6 added <a href="https://github.com/rails/rails/pull/34480">implicit_order_column</a>
on <code>ActiveRecord::ModelSchema</code> which allows us to define a custom column for
implicit ordering on the model level. If there is no <code>implicit_order_column</code>
defined, Rails takes a primary key as the implicit order column. Also, before
Rails 6, the primary key was used to order records implicitly by default.</p>
<p>This has impact on methods like
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/FinderMethods.html#method-i-first">first</a>
,
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/FinderMethods.html#method-i-last">last</a>
and
<a href="https://edgeapi.rubyonrails.org/classes/ActiveRecord/FinderMethods.html">many more</a>
where implicit ordering is used.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   validates :name, presence: true
&gt;&gt; end

=&gt; {:presence=&gt;true}

&gt;&gt; User.first
SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;id&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;User id: 1, name: &quot;Amit&quot;, created_at: &quot;2019-03-11 00:18:41&quot;, updated_at: &quot;2019-03-11 00:18:41&quot;&gt;

&gt;&gt; User.last
SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;id&quot; DESC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;User id: 2, name: &quot;Mark&quot;, created_at: &quot;2019-03-11 00:20:42&quot;, updated_at: &quot;2019-03-11 00:20:42&quot;&gt;

&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   validates :name, presence: true
&gt;&gt;   self.implicit_order_column = &quot;updated_at&quot;
&gt;&gt; end

=&gt; Traceback (most recent call last):
        2: from (irb):10
        1: from (irb):12:in '&lt;class:User&gt;'
NoMethodError (undefined method 'implicit_order_column=' for #&lt;Class:0x00007faf4d6cb408&gt;)
</code></pre>
<h4>Rails 6.0.0.beta2</h4>
<pre><code class="language-ruby">&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   validates :name, presence: true
&gt;&gt; end

=&gt; {:presence=&gt;true}

&gt;&gt; User.first
SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;id&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;User id: 1, name: &quot;Amit&quot;, created_at: &quot;2019-03-11 00:18:41&quot;, updated_at: &quot;2019-03-11 00:18:41&quot;&gt;

&gt;&gt; User.last
SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;id&quot; DESC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;User id: 2, name: &quot;Mark&quot;, created_at: &quot;2019-03-11 00:20:42&quot;, updated_at: &quot;2019-03-11 00:20:42&quot;&gt;

&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   validates :name, presence: true
&gt;&gt;   self.implicit_order_column = &quot;updated_at&quot;
&gt;&gt; end

=&gt; &quot;updated_at&quot;

&gt;&gt; User.find(1).touch
SELECT &quot;users&quot;.* FROM &quot;users&quot; WHERE &quot;users&quot;.&quot;id&quot; = $1 LIMIT $2  [[&quot;id&quot;, 1], [&quot;LIMIT&quot;, 1]]
UPDATE &quot;users&quot; SET &quot;updated_at&quot; = $1 WHERE &quot;users&quot;.&quot;id&quot; = $2  [[&quot;updated_at&quot;, &quot;2019-03-11 00:23:33.369021&quot;], [&quot;id&quot;, 1]]

=&gt; true

&gt;&gt; User.first
SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;updated_at&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;User id: 2, name: &quot;Mark&quot;, created_at: &quot;2019-03-11 00:20:42&quot;, updated_at: &quot;2019-03-11 00:23:09&quot;&gt;

&gt;&gt; User.last
SELECT &quot;users&quot;.* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;updated_at&quot; DESC LIMIT $1  [[&quot;LIMIT&quot;, 1]]

=&gt; #&lt;User id: 1, name: &quot;Amit&quot;, created_at: &quot;2019-03-11 00:18:41&quot;, updated_at: &quot;2019-03-11 00:23:33&quot;&gt;

</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/34480">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Bulk insert support in Rails 6]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/bulk-insert-support-in-rails-6"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/bulk-insert-support-in-rails-6.png"/>
      <id>https://www.bigbinary.com/blog/bulk-insert-support-in-rails-6</id>
      <published>2019-04-15T00:00:00.000Z</published>
      <updated>2019-04-15T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/bulk-insert-support-in-rails-6.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 introduced methods such as insert_all, insert_all! and update_all to support bulk insert]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/bulk-insert-support-in-rails-6"><![CDATA[<p>Rails 6 has added support for bulk inserts similar to how bulk update is
supported using <code>update_all</code> and bulk delete is supported using <code>delete_all</code>.</p>
<p>Bulk inserts can be performed using newly added methods: <code>insert_all</code>,
<code>insert_all!</code> and <code>upsert_all</code>.</p>
<p>All of these new methods allow the insertion of multiple records of the same
model into the database. A single <code>INSERT</code> SQL query is prepared by these
methods and a single sql statement is sent to the database, without
instantiating the model or invoking Active Record callbacks or validations.</p>
<p>During bulk insertion, violation of primary key, violation of unique indexes,
and violation of unique constraints is possible. Rails leverages
database-specific features to either skip, or upsert the duplicates, depending
on the case.</p>
<p>Let's discuss <code>insert_all</code>, <code>insert_all!</code> and <code>upsert_all</code> methods in detail,
which are all used to perform bulk insert.</p>
<p>We will create an <code>articles</code> table with two unique indexes.</p>
<pre><code class="language-ruby">create_table :articles do |t|
  t.string :title, null: false
  t.string :slug, null: false
  t.string :author, null: false
  t.text :description

  t.index :slug, unique: true
  t.index [:title, :author], unique: true
end
</code></pre>
<p>Note that we do not allow duplicate <code>slug</code> columns. We also prevent records from
having duplicate <code>title</code> and <code>author</code> columns together.</p>
<p>To try out the examples provided in this blog post, please ensure to always
clean up the <code>articles</code> table before running any example.</p>
<h2>1. Performing bulk inserts by skipping duplicates</h2>
<p>Let's say we want to insert multiple articles at once into the database. It is
possible that certain records may violate the unique constraint(s) of the table.
Such records are considered duplicates.</p>
<p>In other words, rows or records are determined to be unique by every unique
index on the table by default.</p>
<p>To skip the duplicate rows or records, and insert the rest of the records at
once, we can use <code>ActiveRecord::Persistence#insert_all</code> method.</p>
<h5>1.1 Behavior with PostgreSQL</h5>
<p>Let's run the following example on a PostgreSQL database.</p>
<pre><code class="language-ruby">result = Article.insert_all(
  [
    { id: 1,
      title: 'Handling 1M Requests Per Second',
      author: 'John',
      slug: '1m-req-per-second' },

    { id: 1, # duplicate 'id' here
      title: 'Type Safety in Elm',
      author: 'George',
      slug: 'elm-type-safety' },

    { id: 2,
      title: 'Authentication with Devise - Part 1',
      author: 'Laura',
      slug: 'devise-auth-1' },

    { id: 3,
      title: 'Authentication with Devise - Part 1',
      author: 'Laura', # duplicate 'title' &amp; 'author' here
      slug: 'devise-auth-2' },

    { id: 4,
      title: 'Dockerizing and Deploying Rails App to Kubernetes',
      author: 'Paul',
      slug: 'rails-on-k8s' },

    { id: 5,
      title: 'Elm on Rails',
      author: 'Amanda',
      slug: '1m-req-per-second' }, # duplicate 'slug' here

    { id: 6,
      title: 'Working Remotely',
      author: 'Greg',
      slug: 'working-remotely' }
  ]
)
# Bulk Insert (2.3ms)  INSERT INTO &quot;articles&quot;(&quot;id&quot;,&quot;title&quot;,&quot;author&quot;,&quot;slug&quot;) VALUES (1, 'Handling 1M Requests  [...snip...] 'working-remotely') ON CONFLICT  DO NOTHING RETURNING &quot;id&quot;

puts result.inspect
#&lt;ActiveRecord::Result:0x00007fb6612a1ad8 @columns=[&quot;id&quot;], @rows=[[1], [2], [4], [6]], @hash_rows=nil, @column_types={&quot;id&quot;=&gt;#&lt;ActiveModel::Type::Integer:0x00007fb65f420078 @precision=nil, @scale=nil, @limit=8, @range=-9223372036854775808...9223372036854775808&gt;}&gt;

puts Article.count
# 4
</code></pre>
<p>The <code>insert_all</code> method accepts a mandatory argument which should be an array of
hashes with the attributes of the same model. The keys in all hashes should be
same.</p>
<p>Notice the <code>ON CONFLICT DO NOTHING</code> clause in the <code>INSERT</code> query. This clause is
supported by PostgreSQL and SQLite databases. This instructs the database that
when there is a conflict or a unique key constraint violation during bulk insert
operation, to skip the conflicting record silently and proceed with the
insertion of the next record.</p>
<p>In the above example, we have exactly 3 records which violate various unique
constraints defined on the <code>articles</code> table.</p>
<p>One of the records being inserted has a duplicate <code>id: 1</code> attribute, which
violates unique primary key constraint. Another record that has duplicate
<code>title: 'Authentication with Devise - Part 1', author: 'Laura'</code> attributes
violates the multi-column unique index defined on <code>title</code> and <code>author</code> columns.
Another record has duplicate <code>slug: '1m-req-per-second'</code> attributes violates the
unique index defined on the <code>slug</code> column.</p>
<p>All of these records that violate any unique constraint or unique index are
skipped and are not inserted into the database.</p>
<p>If successful, <code>ActiveRecord::Persistence#insert_all</code> returns an instance of
<code>ActiveRecord::Result</code>. The contents of the result vary per database. In case of
PostgreSQL database, this result instance holds information about the
successfully inserted records such as the chosen column names, values of the
those columns in each successfully inserted row, etc.</p>
<p>For PostgreSQL, by default, <code>insert_all</code> method appends <code>RETURNING &quot;id&quot;</code> clause
to the SQL query where <code>id</code> is the primary key(s). This clause instructs the
database to return the <code>id</code> of every successfully inserted record. By inspecting
the result, especially the <code>@columns=[&quot;id&quot;], @rows=[[1], [2], [4], [6]]</code>
attributes of the result instance, we can see that the records having <code>id</code>
attribute with values <code>1, 2, 4 and 6</code> were successfully inserted.</p>
<p>What if we want to see more attributes and not just the <code>id</code> attribute of the
successfully inserted records in the result?</p>
<p>We should use the optional <code>returning</code> option, which accepts an array of
attribute names, which should be returned for all successfully inserted records!</p>
<pre><code class="language-ruby">result = Article.insert_all(
  [
    { id: 1,
      title: 'Handling 1M Requests Per Second',
      author: 'John',
      slug: '1m-req-per-second' },
    #...snip...
  ],
  returning: %w[ id title ]
)
# Bulk Insert (2.3ms)  INSERT INTO &quot;articles&quot;(&quot;id&quot;,&quot;title&quot;,&quot;author&quot;,&quot;slug&quot;) VALUES (1, 'Handling 1M Requests  [...snip...] 'working-remotely') ON CONFLICT  DO NOTHING RETURNING &quot;id&quot;,&quot;title&quot;

puts result.inspect
#&lt;ActiveRecord::Result:0x00007f902a1196f0 @columns=[&quot;id&quot;, &quot;title&quot;], @rows=[[1, &quot;Handling 1M Requests Per Second&quot;], [2, &quot;Authentication with Devise - Part 1&quot;], [4, &quot;Dockerizing and Deploying Rails App to Kubernetes&quot;], [6, &quot;Working Remotely&quot;]], @hash_rows=nil, @column_types={&quot;id&quot;=&gt;#&lt;ActiveModel::Type::Integer:0x00007f90290ca8d0 @precision=nil, @scale=nil, @limit=8, @range=-9223372036854775808...9223372036854775808&gt;, &quot;title&quot;=&gt;#&lt;ActiveModel::Type::String:0x00007f9029978298 @precision=nil, @scale=nil, @limit=nil&gt;}&gt;

puts result.pluck(&quot;id&quot;, &quot;title&quot;).inspect
#[[1, &quot;Handling 1M Requests Per Second&quot;], [2, &quot;Authentication with Devise - Part 1&quot;], [4, &quot;Dockerizing and Deploying Rails App to Kubernetes&quot;], [6, &quot;Working Remotely&quot;]]
</code></pre>
<p>Notice how the <code>INSERT</code> query appends <code>RETURNING &quot;id&quot;,&quot;title&quot;</code> clause and the
result now holds the <code>id</code> and <code>title</code> attributes of the successfully inserted
records.</p>
<h5>1.2 Behavior with SQLite</h5>
<p>Similar to PostgreSQL, the violating records are skipped during the bulk insert
operation performed using <code>insert_all</code> when we run our example on a SQLite
database.</p>
<pre><code class="language-ruby">result = Article.insert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' },
    { id: 1, title: 'Type Safety in Elm', author: 'George', slug: 'elm-type-safety' }, # duplicate 'id' here
    #...snip...
  ]
)
# Bulk Insert (1.6ms)  INSERT INTO &quot;articles&quot;(&quot;id&quot;,&quot;title&quot;,&quot;author&quot;,&quot;slug&quot;) VALUES (1, 'Handling 1M Requests [...snip...] 'working-remotely') ON CONFLICT  DO NOTHING

puts result.inspect
#&lt;ActiveRecord::Result:0x00007fa9df448ff0 @columns=[], @rows=[], @hash_rows=nil, @column_types={}&gt;

puts Article.pluck(:id, :title)
#[[1, &quot;Handling 1M Requests Per Second&quot;], [2, &quot;Authentication with Devise - Part 1&quot;], [4, &quot;Dockerizing and Deploying Rails App to Kubernetes&quot;], [6, &quot;Working Remotely&quot;]]

puts Article.count
# 4
</code></pre>
<p>Note that since SQLite does not support <code>RETURING</code> clause, it is not being added
to the SQL query. Therefore, the returned <code>ActiveRecord::Result</code> instance does
not contain any useful information.</p>
<p>If we try to explicitly use the <code>returning</code> option when the database being used
is SQLite, then the <code>insert_all</code> method throws an error.</p>
<pre><code class="language-ruby">Article.insert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' },
    #...snip...
  ],
  returning: %w[ id title ]
)
# ActiveRecord::ConnectionAdapters::SQLite3Adapter does not support :returning (ArgumentError)
</code></pre>
<h5>1.3 Behavior with MySQL</h5>
<p>The records that violate primary key, unique key constraints, or unique indexes
are skipped during bulk insert operation performed using <code>insert_all</code> on a MySQL
database.</p>
<pre><code class="language-ruby">result = Article.insert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' },
    { id: 1, title: 'Type Safety in Elm', author: 'George', slug: 'elm-type-safety' }, # duplicate 'id' here
    #...snip...
  ]
)
# Bulk Insert (20.3ms)  INSERT INTO `articles`(`id`,`title`,`author`,`slug`) VALUES (1, 'Handling 1M Requests [...snip...] 'working-remotely') ON DUPLICATE KEY UPDATE `id`=`id`

puts result.inspect
#&lt;ActiveRecord::Result:0x000055d6cfea7580 @columns=[], @rows=[], @hash_rows=nil, @column_types={}&gt;

puts Article.pluck(:id, :title)
#[[1, &quot;Handling 1M Requests Per Second&quot;], [2, &quot;Authentication with Devise - Part 1&quot;], [4, &quot;Dockerizing and Deploying Rails App to Kubernetes&quot;], [6, &quot;Working Remotely&quot;]]

puts Article.count
# 4
</code></pre>
<p>Here, the <code>ON DUPLICATE KEY UPDATE 'id'='id'</code> clause in the <code>INSERT</code> query is
essentially doing the same thing as the <code>ON CONFLICT DO NOTHING</code> clause
supported by PostgreSQL and SQLite.</p>
<p>Since MySQL does not support <code>RETURING</code> clause, it is not being included in the
SQL query and therefore, the result doesn't contain any useful information.</p>
<p>Explicitly trying to use <code>returning</code> option with <code>insert_all</code> method on a MySQL
database throws
<code>ActiveRecord::ConnectionAdapters::Mysql2Adapter does not support :returning</code>
error.</p>
<h2>2. Performing bulk inserts by skipping duplicates on a specified unique constraint but raising exception if records violate other unique constraints</h2>
<p>In the previous case, we were skipping the records that were violating any
unique constraints. In some case, we may want to skip duplicates caused by only
a specific unique index but abort transaction if the other records violate any
other unique constraints.</p>
<p>The optional <code>unique_by</code> option of the <code>insert_all</code> method allows to define such
a unique constraint.</p>
<h5>2.1 Behavior with PostgreSQL and SQLite</h5>
<p>Let's see an example to skip duplicate records that violate only the specified
unique index <code>:index_articles_on_title_and_author</code> using <code>unique_by</code> option. The
duplicate records that do not violate <code>index_articles_on_title_and_author</code> index
are not skipped, and therefore throw an error.</p>
<pre><code class="language-ruby">result = Article.insert_all(
  [
    { .... },
    { .... }, # duplicate 'id' here
    { .... },
    { .... }, # duplicate 'title' and 'author' here
    { .... },
    { .... }, # duplicate 'slug' here
    { .... }
  ],
  unique_by: :index_articles_on_title_and_author
)
# PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint &quot;articles_pkey&quot; (ActiveRecord::RecordNotUnique)
# DETAIL:  Key (id)=(1) already exists.
</code></pre>
<p>In case of SQLite, the error appears as shown below.</p>
<pre><code class="language-text"># SQLite3::ConstraintException: UNIQUE constraint failed: articles.id (ActiveRecord::RecordNotUnique)
</code></pre>
<p>In this case we get <code>ActiveRecord::RecordNotUnique</code> error which is caused by the
violation of primary key constraint on the <code>id</code> column.</p>
<p>It didn't skip the second record in the example above which violated the unique
index on primary key <code>id</code> since the <code>unique_by</code> option was specified with a
different unique index.</p>
<p>When an exception occurs, no record persists to the database since <code>insert_all</code>
executes just a single SQL query.</p>
<p>The <code>unique_by</code> option can be identified by columns or a unique index name.</p>
<p><code>~~~ruby</code> unique_by: :index_articles_on_title_and_author</p>
<h2>is same as</h2>
<p>unique_by: %i[ title author ]</p>
<h2>Also,</h2>
<p>unique_by: :slug</p>
<h2>is same as</h2>
<p>unique_by: %i[ :slug ]</p>
<h2>and also same as</h2>
<p>unique_by: :index_articles_on_slug</p>
<pre><code class="language-ruby">
Let's remove (or fix) the record that has duplicate primary key
and
re-run the above example.

~~~ruby
result = Article.insert_all(
  [
    { .... },
    { .... },
    { .... },
    { .... }, # duplicate 'title' and 'author' here
    { .... },
    { .... }, # duplicate 'slug' here
    { .... }
  ],
  unique_by: :index_articles_on_title_and_author
)
# PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint &quot;index_articles_on_slug&quot; (ActiveRecord::RecordNotUnique)
# DETAIL:  Key (slug)=(1m-req-per-second) already exists.
</code></pre>
<p>In case of SQLite, the error looks appears as shown below.</p>
<pre><code class="language-ruby"># SQLite3::ConstraintException: UNIQUE constraint failed: articles.slug (ActiveRecord::RecordNotUnique)
</code></pre>
<p>The <code>ActiveRecord::RecordNotUnique</code> error in the example above now says the
<code>index_articles_on_slug</code> unique constraint is violated. Note how it
intentionally didn't raise an error for the unique constraint violated on the
<code>title</code> and <code>author</code> columns by the fourth record in the examples above.</p>
<p>Now we will remove (or fix) the record that has same slug.</p>
<pre><code class="language-ruby">result = Article.insert_all(
  [
    { .... },
    { .... },
    { .... },
    { .... }, # duplicate 'title' and 'author' here
    { .... },
    { .... },
    { .... }
  ],
  unique_by: :index_articles_on_title_and_author
)
# Bulk Insert (2.5ms)  INSERT INTO &quot;articles&quot;(&quot;id&quot;,&quot;title&quot;,&quot;author&quot;,&quot;slug&quot;) VALUES (1, 'Handling 1M Requests Per Second', [...snip...] 'working-remotely') ON CONFLICT (&quot;title&quot;,&quot;author&quot;) DO NOTHING RETURNING &quot;id&quot;

puts result.inspect
#&lt;ActiveRecord::Result:0x00007fada2069828 @columns=[&quot;id&quot;], @rows=[[1], [7], [2], [4], [5], [6]], @hash_rows=nil, @column_types={&quot;id&quot;=&gt;#&lt;ActiveModel::Type::Integer:0x00007fad9fdb9df0 @precision=nil, @scale=nil, @limit=8, @range=-9223372036854775808...9223372036854775808&gt;}&gt;
</code></pre>
<p>Here, the fourth record was skipped since that record violates the unique index
<code>index_articles_on_title_and_author</code> specified by the <code>unique_by</code> option.</p>
<p>Similarly, we can specify a different unique index using the <code>unique_by</code> option.
For example, if we specify <code>unique_by: :slug</code> option then the records containing
duplicate <code>slug</code> columns will be skipped, but would raise
<code>ActiveRecord::RecordNotUnique</code> exception if any record violates other unique
constraints.</p>
<h5>2.2 Behavior with MySQL</h5>
<p>The <code>unique_by</code> option is not supported when the database is MySQL.</p>
<h2>3. Raising exception if any of the records being bulk inserted violate any unique constraints</h2>
<p>The <code>insert_all!</code> method (with bang version) never skips a duplicate record. If
a record violates any unique constraints, then <code>insert_all!</code> method would simply
throw an <code>ActiveRecord::RecordNotUnique</code> error.</p>
<p>When database is PostgreSQL, <code>insert_all!</code> method can accept optional
<code>returning</code> option, which we discussed in depth in 1.1 section above.</p>
<p>The <code>unique_by</code> option is not supported by the <code>insert_all!</code> method.</p>
<h2>4. Performing bulk upserts (updates or inserts)</h2>
<p>So far, in the sections 1, 2 and 3 above, we discussed either skipping the
duplicates or raising an exception if a duplicate is encountered during bulk
inserts. Sometimes, we want to update the existing record when a duplicate
occurs otherwise insert a new record. This operation is called upsert because
either it tries to update the record, or if there is no record to update, then
it tries to insert.</p>
<p>The <code>upsert_all</code> method in Rails 6 allows performing bulk upserts.</p>
<p>Let's see it's usage and behavior with different database systems.</p>
<h6>4.1 <code>upsert_all</code> in MySQL</h6>
<p>Let's try to bulk upsert multiple articles containing some duplicates.</p>
<pre><code class="language-ruby">result = Article.upsert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' },
    { id: 1, .... }, # duplicate 'id' here
    { id: 2, .... },
    { id: 3, .... }, # duplicate 'title' and 'author' here
    { id: 4, .... },
    { id: 5, .... }, # duplicate 'slug' here
    { id: 6, .... }
  ]
)
# Bulk Insert (26.3ms)  INSERT INTO `articles`(`id`,`title`,`author`,`slug`) VALUES (1, 'Handling 1M Requests Per Second', 'John', [...snip...] 'working-remotely') ON DUPLICATE KEY UPDATE `title`=VALUES(`title`),`author`=VALUES(`author`),`slug`=VALUES(`slug`)

puts result.inspect
#&lt;ActiveRecord::Result:0x000055a43c1fae10 @columns=[], @rows=[], @hash_rows=nil, @column_types={}&gt;

puts Article.count
# 5

puts Article.all
#&lt;ActiveRecord::Relation [#&lt;Article id: 1, title: &quot;Type Safety in Elm&quot;, slug: &quot;elm-type-safety&quot;, author: &quot;George&quot;, description: nil&gt;, #&lt;Article id: 2, title: &quot;Authentication with Devise - Part 1&quot;, slug: &quot;devise-auth-2&quot;, author: &quot;Laura&quot;, description: nil&gt;, #&lt;Article id: 4, title: &quot;Dockerizing and Deploying Rails App to Kubernetes&quot;, slug: &quot;rails-on-k8s&quot;, author: &quot;Paul&quot;, description: nil&gt;, #&lt;Article id: 5, title: &quot;Elm on Rails&quot;, slug: &quot;1m-req-per-second&quot;, author: &quot;Amanda&quot;, description: nil&gt;, #&lt;Article id: 6, title: &quot;Working Remotely&quot;, slug: &quot;working-remotely&quot;, author: &quot;Greg&quot;, description: nil&gt;]&gt;
</code></pre>
<p>The persisted records in the database look exactly as intended. Let's discuss it
in detail.</p>
<p>The second row in the input array that has the <code>id: 1</code> attribute replaced the
first row, which also had the duplicate <code>id: 1</code> attribute.</p>
<p>The fourth row that has <code>id: 3</code> replaced the attributes of the third row since
both had duplicate &quot;title&quot; and &quot;author&quot; attributes.</p>
<p>The rest of the rows were not duplicates or no longer became duplicates, and
therefore were inserted without any issues.</p>
<p>Note that the <code>returning</code> and <code>unique_by</code> options are not supported in the
<code>upsert_all</code> method when the database is MySQL.</p>
<h6>4.2 <code>upsert_all</code> in SQLite</h6>
<p>Let's try to execute the same example from the above section 4.1 when database
is SQLite.</p>
<pre><code class="language-ruby">result = Article.upsert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' },
    { id: 1, title: 'Type Safety in Elm', author: 'George', slug: 'elm-type-safety' }, # duplicate 'id' here
    { id: 2, title: 'Authentication with Devise - Part 1', author: 'Laura', slug: 'devise-auth-1' },
    { id: 3, title: 'Authentication with Devise - Part 1', author: 'Laura', slug: 'devise-auth-2' }, # duplicate 'title' and 'author' here
    { id: 4, title: 'Dockerizing and Deploying Rails App to Kubernetes', author: 'Paul', slug: 'rails-on-k8s' },
    { id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, # duplicate 'slug' here
    { id: 6, title: 'Working Remotely', author: 'Greg', slug: 'working-remotely' }
  ]
)
# Bulk Insert (4.0ms)  INSERT INTO &quot;articles&quot;(&quot;id&quot;,&quot;title&quot;,&quot;author&quot;,&quot;slug&quot;) VALUES (1, 'Handling 1M Requests Per Second', [...snip...] 'working-remotely') ON CONFLICT (&quot;id&quot;) DO UPDATE SET &quot;title&quot;=excluded.&quot;title&quot;,&quot;author&quot;=excluded.&quot;author&quot;,&quot;slug&quot;=excluded.&quot;slug&quot;

# SQLite3::ConstraintException: UNIQUE constraint failed: articles.title, articles.author (ActiveRecord::RecordNotUnique)
</code></pre>
<p>The bulk upsert operation failed in the above example due to
<code>ActiveRecord::RecordNotUnique</code> exception.</p>
<p>Why it didn't work similar to MySQL?</p>
<p>As per the documentation of MySQL, an upsert operation takes place if a new
record violates any unique constraint.</p>
<p>Whereas, in case of SQLite, by default, new record replaces existing record when
both the existing and new record have the same primary key. If a record violates
any other unique constraints other than the primary key, it then raises
<code>ActiveRecord::RecordNotUnique</code> exception.</p>
<p>The <code>ON CONFLICT (&quot;id&quot;) DO UPDATE</code> clause in the SQL query above conveys the
same intent.</p>
<p>Therefore, <code>upsert_all</code> in SQLite doesn't behave exactly same as in MySQL.</p>
<p>As a workaround, we will need to upsert records with the help of multiple
<code>upsert_all</code> calls with the usage of <code>unique_by</code> option.</p>
<p>If a duplicate record is encountered during the upsert operation, which violates
the unique index specified using <code>unique_by</code> option then it will replace the
attributes of the existing matching record.</p>
<p>Let's try to understand this workaround with another example.</p>
<pre><code class="language-ruby">Article.upsert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' },
    { id: 1, title: 'Type Safety in Elm', author: 'George', slug: 'elm-type-safety' }, # duplicate 'id' here
  ],
  unique_by: :id
)

Article.upsert_all(
  [
    { id: 2, title: 'Authentication with Devise - Part 1', author: 'Laura', slug: 'devise-auth-1' },
    { id: 3, title: 'Authentication with Devise - Part 1', author: 'Laura', slug: 'devise-auth-2' }, # duplicate 'title' and 'author' here
    { id: 4, title: 'Dockerizing and Deploying Rails App to Kubernetes', author: 'Paul', slug: 'rails-on-k8s' },
    { id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, # duplicate 'slug' here
    { id: 6, title: 'Working Remotely', author: 'Greg', slug: 'working-remotely' }
  ],
  unique_by: %i[ title author ]
)

puts Article.count
# 5

puts Article.all
#&lt;ActiveRecord::Relation [#&lt;Article id: 1, title: &quot;Type Safety in Elm&quot;, slug: &quot;elm-type-safety&quot;, author: &quot;George&quot;, description: nil&gt;, #&lt;Article id: 2, title: &quot;Authentication with Devise - Part 1&quot;, slug: &quot;devise-auth-2&quot;, author: &quot;Laura&quot;, description: nil&gt;, #&lt;Article id: 4, title: &quot;Dockerizing and Deploying Rails App to Kubernetes&quot;, slug: &quot;rails-on-k8s&quot;, author: &quot;Paul&quot;, description: nil&gt;, #&lt;Article id: 5, title: &quot;Elm on Rails&quot;, slug: &quot;1m-req-per-second&quot;, author: &quot;Amanda&quot;, description: nil&gt;, #&lt;Article id: 6, title: &quot;Working Remotely&quot;, slug: &quot;working-remotely&quot;, author: &quot;Greg&quot;, description: nil&gt;]&gt;
</code></pre>
<p>Here, we first tried to upsert all the records which violated the unique primary
key index on <code>id</code> column. Later, we upsert successfully all the remaining
records, which violated the unique index on the <code>title</code> and <code>author</code> columns.</p>
<p>Note that since the first record's <code>slug</code> attribute was already replaced with
the second record's <code>slug</code> attribute; the last second record having <code>id: 5</code>
didn't raise an exception because of duplicate <code>slug</code> column.</p>
<h6>4.3 <code>upsert_all</code> in PostgreSQL</h6>
<p>We will run the same example in the 4.1 section above with PostgreSQL database.</p>
<pre><code class="language-ruby">result = Article.upsert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' },
    { id: 1, title: 'Type Safety in Elm', author: 'George', slug: 'elm-type-safety' }, # duplicate 'id' here
    { id: 2, title: 'Authentication with Devise - Part 1', author: 'Laura', slug: 'devise-auth-1' },
    { id: 3, title: 'Authentication with Devise - Part 1', author: 'Laura', slug: 'devise-auth-2' }, # duplicate 'title' and 'author' here
    { id: 4, title: 'Dockerizing and Deploying Rails App to Kubernetes', author: 'Paul', slug: 'rails-on-k8s' },
    { id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, # duplicate 'slug' here
    { id: 6, title: 'Working Remotely', author: 'Greg', slug: 'working-remotely' }
  ]
)
# PG::CardinalityViolation: ERROR:  ON CONFLICT DO UPDATE command cannot affect row a second time (ActiveRecord::StatementInvalid)
# HINT:  Ensure that no rows proposed for insertion within the same command have duplicate constrained values.
</code></pre>
<p>The bulk upsert operation failed in the above example due to
<code>ActiveRecord::StatementInvalid</code> exception which was caused by another
<code>PG::CardinalityViolation</code> exception.</p>
<p>The <code>PG::CardinalityViolation</code> exception originates from
<a href="https://github.com/postgres/postgres/blob/beeb8e2e0717065296dc7b32daba2d66f0f931dd/src/backend/executor/nodeModifyTable.c#L1335-L1355">here</a>.</p>
<p>The <code>PG::CardinalityViolation</code> exception occurs when a row cannot be updated a
second time in the same <code>ON CONFLICT DO UPDATE</code> SQL query. PostgreSQL assumes
this behavior would lead the same row to updated a second time in the same SQL
query, in unspecified order, non-deterministically.</p>
<p>PostgreSQL recommends it is the developer's responsibility to prevent this
situation from occurring.</p>
<p>Here's more discussion about this issue -
<a href="https://github.com/rails/rails/issues/35519">rails/rails#35519</a>.</p>
<p>Therefore, the <code>upsert_all</code> method doesn't work as intended due to the above
limitation in PostgreSQL.</p>
<p>As a workaround, we can divide the single <code>upsert_all</code> query into multiple
<code>upsert_all</code> queries with the use of <code>unique_by</code> option similar to how we did in
case of SQLite in the 4.2 section above.</p>
<pre><code class="language-ruby">Article.insert_all(
  [
    { id: 1, title: 'Handling 1M requests per second', author: 'John', slug: '1m-req-per-second' },
    { id: 2, title: 'Authentication with Devise - Part 1', author: 'Laura', slug: 'devise-auth-1' },
    { id: 4, title: 'Dockerizing and deploy Rails app to Kubernetes', author: 'Paul', slug: 'rails-on-k8s' },
    { id: 6, title: 'Working Remotely', author: 'Greg', slug: 'working-remotely' }
  ]
)

Article.upsert_all(
  [
    { id: 1, title: 'Type Safety in Elm', author: 'George', slug: 'elm-type-safety' }, # duplicate 'id' here
  ]
)

Article.upsert_all(
  [
    { id: 3, title: 'Authentication with Devise - Part 1', author: 'Laura', slug: 'devise-auth-2' }, # duplicate 'title' and 'author' here
  ],
  unique_by: :index_articles_on_title_and_author
)

Article.upsert_all(
  [
    { id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, # duplicate 'slug' here
  ]
)

puts Article.count
# 5

puts Article.all
#&lt;ActiveRecord::Relation [#&lt;Article id: 1, title: &quot;Type Safety in Elm&quot;, slug: &quot;elm-type-safety&quot;, author: &quot;George&quot;, description: nil&gt;, #&lt;Article id: 2, title: &quot;Authentication with Devise - Part 1&quot;, slug: &quot;devise-auth-2&quot;, author: &quot;Laura&quot;, description: nil&gt;, #&lt;Article id: 4, title: &quot;Dockerizing and deploy Rails app to Kubernetes&quot;, slug: &quot;rails-on-k8s&quot;, author: &quot;Paul&quot;, description: nil&gt;, #&lt;Article id: 5, title: &quot;Elm on Rails&quot;, slug: &quot;1m-req-per-second&quot;, author: &quot;Amanda&quot;, description: nil&gt;, #&lt;Article id: 6, title: &quot;Working Remotely&quot;, slug: &quot;working-remotely&quot;, author: &quot;Greg&quot;, description: nil&gt;]&gt;
</code></pre>
<p>For reference, note that the <code>upsert_all</code> method also accepts <code>returning</code> option
for PostgreSQL which we have already discussed in the 1.1 section above.</p>
<h2>5. <code>insert</code>, <code>insert!</code> and <code>upsert</code></h2>
<p>Rails 6 has also introduced three more additional methods namely <code>insert</code>,
<code>insert!</code> and <code>upsert</code> for convenience.</p>
<p>The <code>insert</code> method inserts a single record into the database. If that record
violates a uniqueness constrain, then the <code>insert</code> method will skip inserting
record into the database without raising an exception.</p>
<p>Similarly, the <code>insert!</code> method also inserts a single record into the database,
but will raise <code>ActiveRecord::RecordNotUnique</code> exception if that record violates
a uniqueness constraint.</p>
<p>The <code>upsert</code> method inserts or updates a single record into the database similar
to how <code>upsert_all</code> does.</p>
<p>The methods <code>insert</code>, <code>insert!</code> and <code>upsert</code> are wrappers around <code>insert_all</code>,
<code>insert_all!</code> and <code>upsert_all</code> respectively.</p>
<p>Let's see some examples to understand the usage of these methods.</p>
<pre><code class="language-ruby">Article.insert({ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, unique_by: :slug)

# is same as

Article.insert_all([{ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }], unique_by: :slug)
</code></pre>
<pre><code class="language-ruby">Article.insert!({ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, returning: %w[ id title ])

# is same as

Article.insert_all!([{ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }], returning: %w[ id title ])
</code></pre>
<pre><code class="language-ruby">Article.upsert({ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }, unique_by: :slug, returning: %w[ id title ])

# is same as

Article.upsert_all([{ id: 5, title: 'Elm on Rails', author: 'Amanda', slug: '1m-req-per-second' }], unique_by: :slug, returning: %w[ id title ])
</code></pre>
<hr>
<p>To learn more about the bulk insert feature and its implementation, please check
<a href="https://github.com/rails/rails/pull/35077">rails/rails#35077</a>,
<a href="https://github.com/rails/rails/pull/35546">rails/rails#35546</a> and
<a href="https://github.com/rails/rails/pull/35854">rails/rails#35854</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 drops support for PostgreSQL version less than 9.3]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-drops-support-for-postgresql-less-than-9-3"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-drops-support-for-postgresql-less-than-9-3.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-drops-support-for-postgresql-less-than-9-3</id>
      <published>2019-04-10T00:00:00.000Z</published>
      <updated>2019-04-10T00:00:00.000Z</updated>
      <author>
        <name>Prathamesh Sonpatki</name>
        <uri>https://www.bigbinary.com/blog/authors/prathamesh</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-drops-support-for-postgresql-less-than-9-3.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 has dropped support for PostgreSQL versions less than 9.3]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-drops-support-for-postgresql-less-than-9-3"><![CDATA[<p>Before Rails 6, Rails was supporting PostgreSQL from version 9.1 and above. But
in Rails 6,
<a href="https://github.com/rails/rails/pull/34520">support for versions less than 9.3 is dropped</a>.
If your PostgreSQL version is less than 9.3 then an
<a href="https://travis-ci.org/codetriage/codetriage/jobs/506656780#L1591">error</a> is
shown as follows.</p>
<pre><code class="language-text">Your version of PostgreSQL (90224) is too old. Active Record supports PostgreSQL &gt;= 9.3.
</code></pre>
<p>Travis CI uses
<a href="https://docs.travis-ci.com/user/database-setup/#postgresql">PostgreSQL 9.2</a> by
default in their images. So this error can occur while testing the app on Travis
CI with Rails 6. It can be resolved by using an
<a href="https://github.com/codetriage/codetriage/blob/rails-6/.travis.yml#L12-L13">add-on for PostgreSQL</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 requires Ruby 2.5 or newer]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-requires-ruby-2-5-or-newer"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-requires-ruby-2-5-or-newer.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-requires-ruby-2-5-or-newer</id>
      <published>2019-04-09T00:00:00.000Z</published>
      <updated>2019-04-09T00:00:00.000Z</updated>
      <author>
        <name>Vishal Telangre</name>
        <uri>https://www.bigbinary.com/blog/authors/vishaltelangre</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-requires-ruby-2-5-or-newer.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[As per rails/rails#34754, a Rails 6 app requires Ruby version 2.5 or newer. Let's discuss what we need to know if we are dealing with Rails 6. Ensuring a valid Ruby version is set while creating a...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-requires-ruby-2-5-or-newer"><![CDATA[<p>As per <a href="https://github.com/rails/rails/pull/34754">rails/rails#34754</a>, a Rails 6
app requires Ruby version 2.5 or newer.</p>
<p>Let's discuss what we need to know if we are dealing with Rails 6.</p>
<h2>Ensuring a valid Ruby version is set while creating a new Rails 6 app</h2>
<p>While creating a new Rails 6 app, we need to ensure that the current Ruby
version in the shell is set to 2.5 or newer.</p>
<p>If it is set to an older version then the same version will be used by the
<code>rails new</code> command to set the Ruby version in <code>.ruby-version</code> and in <code>Gemfile</code>
respectively in the created Rails app.</p>
<pre><code class="language-plaintext">\$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]

\$ rails new meme-wizard
create
create README.md
create Rakefile
create .ruby-version
create config.ru
create .gitignore
create Gemfile
[...] omitted the rest of the output

\$ cd meme-wizard &amp;&amp; grep -C 2 -Rn -a &quot;2.3.1&quot; .
./.ruby-version:1:2.3.1
--
--
./Gemfile-2-git_source(:github) { |repo| &quot;https://github.com/#{repo}.git&quot; }
./Gemfile-3-
./Gemfile:4:ruby '2.3.1'
./Gemfile-5-
./Gemfile-6-# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
</code></pre>
<p>An easy fix for this is to install a Ruby version 2.5 or newer and use that
version prior to running the <code>rails new</code> command.</p>
<pre><code class="language-plaintext">\$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]

\$ rbenv local 2.6.0

\$ ruby -v
ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-darwin18]

\$ rails new meme-wizard

\$ cd meme-wizard &amp;&amp; grep -C 2 -Rn -a &quot;2.6.0&quot; .
./.ruby-version:1:2.6.0
--
--
./Gemfile-2-git_source(:github) { |repo| &quot;https://github.com/#{repo}.git&quot; }
./Gemfile-3-
./Gemfile:4:ruby '2.6.0'
./Gemfile-5-
./Gemfile-6-# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
</code></pre>
<h2>Upgrading an older Rails app to Rails 6</h2>
<p>While upgrading an older Rails app to Rails 6, we need to update the Ruby
version to 2.5 or newer in <code>.ruby-version</code> and <code>Gemfile</code> files respectively.</p>
<h2>What else do we need to know?</h2>
<p>Since
<a href="https://blog.bigbinary.com/2018/02/06/ruby-2-5-added-hash-slice-method.html">Ruby 2.5 has added <code>Hash#slice</code> method</a>,
the extension method with the same name defined by
<code>activesupport/lib/active_support/core_ext/hash/slice.rb</code> has been
<a href="https://github.com/rails/rails/pull/34754">removed from Rails 6</a>.</p>
<p>Similarly, Rails 6 has also <a href="https://github.com/rails/rails/pull/32034">removed</a>
the extension methods <code>Hash#transform_values</code> and <code>Hash#transform_values!</code> from
Active Support in favor of the native methods with the same names which exist in
Ruby. These methods were
<a href="https://blog.bigbinary.com/2017/06/14/ruby-2-4-added-hash-transform-values-and-its-destructive-version-from-active-support.html">introduced in Ruby 2.4 natively</a>.</p>
<p>If we try to explicitly require <code>active_support/core_ext/hash/transform_values</code>
then it would print a deprecation warning.</p>
<pre><code class="language-ruby">
&gt; &gt; require &quot;active_support/core_ext/hash/transform_values&quot;

# DEPRECATION WARNING: Ruby 2.5+ (required by Rails 6) provides Hash#transform_values natively, so requiring active_support/core_ext/hash/transform_values is no longer necessary. Requiring it will raise LoadError in Rails 6.1. (called from irb_binding at (irb):1)

=&gt; true
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 database seed uses inline Active Job adapter]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/database-seeding-task-uses-inline-active-job-adapter-in-rails-6"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/database-seeding-task-uses-inline-active-job-adapter-in-rails-6.png"/>
      <id>https://www.bigbinary.com/blog/database-seeding-task-uses-inline-active-job-adapter-in-rails-6</id>
      <published>2019-04-03T00:00:00.000Z</published>
      <updated>2019-04-03T00:00:00.000Z</updated>
      <author>
        <name>Prathamesh Sonpatki</name>
        <uri>https://www.bigbinary.com/blog/authors/prathamesh</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/database-seeding-task-uses-inline-active-job-adapter-in-rails-6.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 uses inline Active Job adapter for background processing related to db:seed task]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/database-seeding-task-uses-inline-active-job-adapter-in-rails-6"><![CDATA[<p>We use the <code>db:seed</code> task to seed the database in Rails apps. Recently an
<a href="https://github.com/rails/rails/issues/34939">issue</a> was reported on Rails issue
tracker where the <code>db:seed</code> task was not finishing.</p>
<p>In development environment, Rails uses
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveJob/QueueAdapters/AsyncAdapter.html">async adapter</a>
as the default Active Job adapter. The Async adapter runs jobs with an
in-process thread pool.</p>
<p>This specific issue was happening because the seed task was trying to attach a
file using Active Storage. Active Storage
<a href="https://github.com/rails/rails/blob/9e34df00039d63b5672315419e76f06f80ef3dc4/activestorage/app/models/active_storage/attachment.rb#L37">adds a job in the background</a>
during the attachment process. This task was not getting executed properly using
the async adapter and it was causing the seed task to hang without exiting.</p>
<p>It was found out that by using the
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveJob/QueueAdapters/InlineAdapter.html">inline</a>
adapter in development environment, this issue goes away. But making a wholesale
change of making the default adapter in development environment as inline
adapter defeats the purpose of having the async adapter as default in the first
place.</p>
<p>Instead a change is made to
<a href="https://github.com/rails/rails/pull/34953">execute all the code related to seeding using inline adapter</a>.
The inline adapter makes sure that all the code will be executed immediately.</p>
<p>As the inline adapter does not allow queuing up the jobs in future, this can
result into an error if the seeding code somehow triggers such jobs. This
<a href="https://github.com/rails/rails/issues/35812#issuecomment-479385857">issue</a> is
already reported on Github.</p>
<h3>Update</h3>
<p>Active Job is optional framework and we can skip it completely. Now that seeding
depends on presence of Active Job, it was throwing an error when Active Job was
not part of the application. Also, executing the jobs inline automatically, when
users has set the Active Job queue adapter to something of their choice was
surprising for the users. So a
<a href="https://github.com/rails/rails/pull/35896">change</a> has been made to load the
seeds inline only when Active Job is included in the application and the queue
adapter is <code>async</code>. This makes it backward compatible as well it does not change
user's choice of queue adapter automatically.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActiveRecord::Relation#reselect]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-activerecord-relation-reselect"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activerecord-relation-reselect.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-activerecord-relation-reselect</id>
      <published>2019-04-02T00:00:00.000Z</published>
      <updated>2019-04-02T00:00:00.000Z</updated>
      <author>
        <name>Abhay Nikam</name>
        <uri>https://www.bigbinary.com/blog/authors/abhay</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activerecord-relation-reselect.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds ActiveRecord::Relation#reselect method.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-activerecord-relation-reselect"><![CDATA[<p>Rails have
<a href="https://apidock.com/rails/ActiveRecord/QueryMethods/rewhere"><code>rewhere</code></a> and
<a href="https://apidock.com/rails/ActiveRecord/QueryMethods/reorder"><code>reorder</code></a> methods
to change the previously set conditions attributes to new attributes which are
given as an argument to method.</p>
<p>Before Rails 6, if you want to change the previously set <code>select</code> statement
attributes to new attributes, it was done as follows.</p>
<pre><code class="language-ruby">&gt;&gt; Post.select(:title, :body).unscope(:select).select(:views)

   SELECT &quot;posts&quot;.&quot;views&quot; FROM &quot;posts&quot; LIMIT ? [&quot;LIMIT&quot;, 1]]
</code></pre>
<p>In Rails 6, <code>ActiveRecord::Relation#reselect</code> method is added.</p>
<p>The <code>reselect</code> method is similar to <code>rewhere</code> and <code>reorder</code>. <code>reselect</code> is a
short-hand for <code>unscope(:select).select(fields)</code>.</p>
<p>Here is how <code>reselect</code> method can be used.</p>
<pre><code class="language-ruby">&gt;&gt; Post.select(:title, :body).reselect(:views)

   SELECT &quot;posts&quot;.&quot;views&quot; FROM &quot;posts&quot; LIMIT ? [&quot;LIMIT&quot;, 1]]
</code></pre>
<p>Check out the <a href="https://github.com/rails/rails/pull/33611">pull request</a> for more
details on this.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActiveModel::Errors#of_kind?]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-activemodel-errors-of_kind-"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activemodel-errors-of_kind-.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-activemodel-errors-of_kind-</id>
      <published>2019-04-01T00:00:00.000Z</published>
      <updated>2019-04-01T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activemodel-errors-of_kind-.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 added ofkind? on ActiveModel::Errors. It returns true if the ActiveModel::Errors object has provided a key and message associated with it. The default message is :invalid. ofkind? is same as...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-activemodel-errors-of_kind-"><![CDATA[<p>Rails 6 added <a href="https://github.com/rails/rails/pull/34866">of_kind?</a> on
<code>ActiveModel::Errors</code>. It returns true if the <code>ActiveModel::Errors</code> object has
provided a key and message associated with it. The default message is
<code>:invalid</code>.</p>
<p><a href="https://github.com/rails/rails/pull/34866">of_kind?</a> is same as
<a href="https://api.rubyonrails.org/classes/ActiveModel/Errors.html#method-i-added-3F">ActiveModel::Errors#added?</a>
but, it doesn't take extra options as a parameter.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 6.0.0.beta2</h4>
<pre><code class="language-ruby">&gt;&gt; class User &lt; ApplicationRecord
&gt;&gt;   validates :name, presence: true
&gt;&gt; end

&gt;&gt; user = User.new

=&gt; =&gt; #&lt;User id: nil, name: nil, password: nil, created_at: nil, updated_at: nil&gt;

&gt;&gt; user.valid?

=&gt; false

&gt;&gt; user.errors

=&gt; #&lt;ActiveModel::Errors:0x00007fc462a1d140 @base=#&lt;User id: nil, name: nil, password: nil, created_at: nil, updated_at: nil&gt;, @messages={:name=&gt;[&quot;can't be blank&quot;]}, @details={:name=&gt;[{:error=&gt;:blank}]}&gt;

&gt;&gt; user.errors.of_kind?(:name)

=&gt; false

&gt;&gt; user.errors.of_kind?(:name, :blank)

=&gt; true

&gt;&gt; user.errors.of_kind?(:name, &quot;can't be blank&quot;)

=&gt; true

&gt;&gt; user.errors.of_kind?(:name, &quot;is blank&quot;)

=&gt; false
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/34866">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 shows routes in expanded format]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-shows-routes-in-expanded-format"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-shows-routes-in-expanded-format.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-shows-routes-in-expanded-format</id>
      <published>2019-03-27T00:00:00.000Z</published>
      <updated>2019-03-27T00:00:00.000Z</updated>
      <author>
        <name>Prathamesh Sonpatki</name>
        <uri>https://www.bigbinary.com/blog/authors/prathamesh</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-shows-routes-in-expanded-format.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 has added ability to show the routes in an expanded format]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-shows-routes-in-expanded-format"><![CDATA[<p>The output of <code>rails routes</code> is in the table format.</p>
<pre><code class="language-bash">$ rails routes
   Prefix Verb   URI Pattern               Controller#Action
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
 new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit
     user GET    /users/:id(.:format)      users#show
          PATCH  /users/:id(.:format)      users#update
          PUT    /users/:id(.:format)      users#update
          DELETE /users/:id(.:format)      users#destroy
</code></pre>
<p>If we have long route names, they don't fit on the terminal window as the output
lines wrap with each other.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-shows-routes-in-expanded-format/overlapping_routes.webp" alt="Example of overlapping routes"></p>
<p>Rails 6 has added a way to display the routes in an
<a href="https://github.com/rails/rails/pull/32130">expanded format</a>.</p>
<p>We can pass <code>--expanded</code> switch to the <code>rails routes</code> command to see this in
action.</p>
<pre><code class="language-bash">$ rails routes --expanded

--[ Route 1 ]--------------------------------------------------------------
Prefix            | users
Verb              | GET
URI               | /users(.:format)
Controller#Action | users#index
--[ Route 2 ]--------------------------------------------------------------
Prefix            |
Verb              | POST
URI               | /users(.:format)
Controller#Action | users#create
--[ Route 3 ]--------------------------------------------------------------
Prefix            | new_user
Verb              | GET
URI               | /users/new(.:format)
Controller#Action | users#new
--[ Route 4 ]--------------------------------------------------------------
Prefix            | edit_user
Verb              | GET
URI               | /users/:id/edit(.:format)
Controller#Action | users#edit

</code></pre>
<p>This shows the output of the routes command in much more user friendly manner.</p>
<p>The <code>--expanded</code> switch can be used in conjunction with
<a href="https://blog.bigbinary.com/2016/02/16/rails-5-options-for-rake-routes.html">other switches for searching specific routes</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds ActiveModel::Errors#slice!]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-activemodel-errors-slice"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activemodel-errors-slice.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-activemodel-errors-slice</id>
      <published>2019-03-26T00:00:00.000Z</published>
      <updated>2019-03-26T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-activemodel-errors-slice.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 added slice! on ActiveModel::Errors. With this addition, it becomes quite easy to select just a few keys from errors and show or return them. Before Rails 6, we needed to convert the...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-activemodel-errors-slice"><![CDATA[<p>Rails 6 added <a href="https://github.com/rails/rails/pull/34489">slice!</a> on
<code>ActiveModel::Errors</code>. With this addition, it becomes quite easy to select just
a few keys from errors and show or return them. Before Rails 6, we needed to
convert the <code>ActiveModel::Errors</code> object to a hash before slicing the keys.</p>
<p>Let's checkout how it works.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">&gt;&gt; user = User.new

=&gt; #&lt;User id: nil, email: nil, password: nil, created_at: nil, updated_at: nil&gt;

&gt;&gt; user.valid?

=&gt; false

&gt;&gt; user.errors

=&gt; #&lt;ActiveModel::Errors:0x00007fc46700df10 @base=#&lt;User id: nil, email: nil, password: nil, created_at: nil, updated_at: nil&gt;, @messages={:email=&gt;[&quot;can't be blank&quot;], :password=&gt;[&quot;can't be blank&quot;]}, @details={:email=&gt;[{:error=&gt;:blank}], :password=&gt;[{:error=&gt;:blank}]}&gt;

&gt;&gt; user.errors.slice!

=&gt; Traceback (most recent call last):
        1: from (irb):16
NoMethodError (undefined method 'slice!' for #&lt;ActiveModel::Errors:0x00007fa1f0e46eb8&gt;)
Did you mean?  slice_when

&gt;&gt; errors = user.errors.to_h
&gt;&gt; errors.slice!(:email)

=&gt; {:password=&gt;[&quot;can't be blank&quot;]}

&gt;&gt; errors

=&gt; {:email=&gt;[&quot;can't be blank&quot;]}
</code></pre>
<h4>Rails 6.0.0.beta2</h4>
<pre><code class="language-ruby">&gt;&gt; user = User.new

=&gt; #&lt;User id: nil, email: nil, password: nil, created_at: nil, updated_at: nil&gt;

&gt;&gt; user.valid?

=&gt; false

&gt;&gt; user.errors

=&gt; #&lt;ActiveModel::Errors:0x00007fc46700df10 @base=#&lt;User id: nil, email: nil, password: nil, created_at: nil, updated_at: nil&gt;, @messages={:email=&gt;[&quot;can't be blank&quot;], :password=&gt;[&quot;can't be blank&quot;]}, @details={:email=&gt;[{:error=&gt;:blank}], :password=&gt;[{:error=&gt;:blank}]}&gt;

&gt;&gt; user.errors.slice!(:email)

=&gt; {:password=&gt;[&quot;can't be blank&quot;]}

&gt;&gt; user.errors

=&gt; #&lt;ActiveModel::Errors:0x00007fc46700df10 @base=#&lt;User id: nil, email: nil, password: nil, created_at: nil, updated_at: nil&gt;, @messages={:email=&gt;[&quot;can't be blank&quot;]}, @details={:email=&gt;[{:error=&gt;:blank}]}&gt;
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/34489">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 adds create_or_find_by and create_or_find_by!]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-adds-create_or_find_by"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-create_or_find_by.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-adds-create_or_find_by</id>
      <published>2019-03-25T00:00:00.000Z</published>
      <updated>2019-03-25T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-adds-create_or_find_by.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 adds create_or_find_by and create_or_find_by! to find record if creation fails because of unique constraints]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-adds-create_or_find_by"><![CDATA[<p>Rails 6 added <a href="https://github.com/rails/rails/pull/31989">create_or_find_by</a> and
<a href="https://github.com/rails/rails/pull/31989">create_or_find_by!</a>. Both of these
methods rely on unique constraints on the database level. If creation fails, it
is because of the unique constraints on one or all of the given columns, and it
will try to find the record using <code>find_by!</code>.</p>
<p><a href="https://github.com/rails/rails/pull/31989">create_or_find_by</a> is an improvement
over
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/Relation.html#method-i-find_or_create_by">find_or_create_by</a>
because
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/Relation.html#method-i-find_or_create_by">find_or_create_by</a>
first queries for the record, and then inserts it if none is found. This could
lead to a race condition.</p>
<p>As mentioned by DHH in the pull request,
<a href="https://github.com/rails/rails/pull/31989">create_or_find_by</a> has a few cons
too:</p>
<ul>
<li>The table must have unique constraints on the relevant columns.</li>
<li>This method relies on exception handling, which is generally slower.</li>
</ul>
<p><a href="https://github.com/rails/rails/pull/31989">create_or_find_by!</a> raises an
exception when creation fails because of the validations.</p>
<p>Let's see how both methods work in Rails 6.0.0.beta2.</p>
<h4>Rails 6.0.0.beta2</h4>
<pre><code class="language-ruby">
&gt; &gt; class CreateUsers &lt; ActiveRecord::Migration[6.0]
&gt; &gt; def change
&gt; &gt; create_table :users do |t|
&gt; &gt; t.string :name, index: { unique: true }
&gt; &gt;
&gt; &gt;       t.timestamps
&gt; &gt;     end
&gt; &gt;
&gt; &gt; end
&gt; &gt; end

&gt; &gt; class User &lt; ApplicationRecord
&gt; &gt; validates :name, presence: true
&gt; &gt; end

&gt; &gt; User.create_or_find_by(name: 'Amit')
&gt; &gt; BEGIN
&gt; &gt; INSERT INTO &quot;users&quot; (&quot;name&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES ($1, $2, \$3) RETURNING &quot;id&quot; [[&quot;name&quot;, &quot;Amit&quot;], [&quot;created_at&quot;, &quot;2019-03-07 09:33:23.391719&quot;], [&quot;updated_at&quot;, &quot;2019-03-07 09:33:23.391719&quot;]]
&gt; &gt; COMMIT

=&gt; #&lt;User id: 1, name: &quot;Amit&quot;, created_at: &quot;2019-03-07 09:33:23&quot;, updated_at: &quot;2019-03-07 09:33:23&quot;&gt;

&gt; &gt; User.create_or_find_by(name: 'Amit')
&gt; &gt; BEGIN
&gt; &gt; INSERT INTO &quot;users&quot; (&quot;name&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES ($1, $2, \$3) RETURNING &quot;id&quot; [[&quot;name&quot;, &quot;Amit&quot;], [&quot;created_at&quot;, &quot;2019-03-07 09:46:37.189068&quot;], [&quot;updated_at&quot;, &quot;2019-03-07 09:46:37.189068&quot;]]
&gt; &gt; ROLLBACK

=&gt; #&lt;User id: 1, name: &quot;Amit&quot;, created_at: &quot;2019-03-07 09:33:23&quot;, updated_at: &quot;2019-03-07 09:33:23&quot;&gt;

&gt; &gt; User.create_or_find_by(name: nil)
&gt; &gt; BEGIN
&gt; &gt; COMMIT

=&gt; #&lt;User id: nil, name: nil, created_at: nil, updated_at: nil&gt;

&gt; &gt; User.create_or_find_by!(name: nil)

=&gt; Traceback (most recent call last):
1: from (irb):2
ActiveRecord::RecordInvalid (Validation failed: Name can't be blank)
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/31989">pull request</a>.</p>
<p>Also note, <a href="https://github.com/rails/rails/pull/31989">create_or_find_by</a> can
lead to primary keys running out, if the type of primary key is <code>int</code>. This
happens because each time
<a href="https://github.com/rails/rails/pull/31989">create_or_find_by</a> hits
<code>ActiveRecord::RecordNotUnique</code>, it does not rollback auto-increment of the
primary key. The problem is discussed in this
<a href="https://github.com/rails/rails/issues/35543">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 raises ActiveModel::MissingAttributeError]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-raises-activemodel-missingattributeerror-when-update_columns-is-used-with-non-existing-attribute"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-raises-activemodel-missingattributeerror-when-update_columns-is-used-with-non-existing-attribute.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-raises-activemodel-missingattributeerror-when-update_columns-is-used-with-non-existing-attribute</id>
      <published>2019-03-20T00:00:00.000Z</published>
      <updated>2019-03-20T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-raises-activemodel-missingattributeerror-when-update_columns-is-used-with-non-existing-attribute.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[updated_columns raises ActiveModel::MissingAttributeError when used with a non-existing attribute in Rails 6]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-raises-activemodel-missingattributeerror-when-update_columns-is-used-with-non-existing-attribute"><![CDATA[<p>Rails 6 raises <code>ActiveModel::MissingAttributeError</code> when
<a href="https://github.com/rails/rails/commit/b63701e272">update_columns</a> is used with
a non-existing attribute. Before Rails 6,
<a href="https://api.rubyonrails.org/v5.2/classes/ActiveRecord/Persistence.html#method-i-update_columns">update_columns</a>
raised an <code>ActiveRecord::StatementInvalid</code> error.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">
&gt; &gt; User.first.update_columns(email: 'amit@bigbinary.com')
&gt; &gt; SELECT &quot;users&quot;.\* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;id&quot; ASC LIMIT $1  [[&quot;LIMIT&quot;, 1]]
UPDATE &quot;users&quot; SET &quot;email&quot; = $1 WHERE &quot;users&quot;.&quot;id&quot; = \$2 [[&quot;email&quot;, &quot;amit@bigbinary.com&quot;], [&quot;id&quot;, 1]]

=&gt; Traceback (most recent call last):
1: from (irb):8
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column &quot;email&quot; of relation &quot;users&quot; does not exist)
LINE 1: UPDATE &quot;users&quot; SET &quot;email&quot; = $1 WHERE &quot;users&quot;.&quot;id&quot; = $2
^
: UPDATE &quot;users&quot; SET &quot;email&quot; = $1 WHERE &quot;users&quot;.&quot;id&quot; = $2
</code></pre>
<h4>Rails 6.0.0.beta2</h4>
<pre><code class="language-ruby">
&gt; &gt; User.first.update_columns(email: 'amit@bigbinary.com')
&gt; &gt; SELECT &quot;users&quot;.\* FROM &quot;users&quot; ORDER BY &quot;users&quot;.&quot;id&quot; ASC LIMIT ? [[&quot;LIMIT&quot;, 1]]

Traceback (most recent call last):
1: from (irb):1
ActiveModel::MissingAttributeError (can't write unknown attribute `email`)
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/commit/b63701e272">commit</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 ActiveRecord::Base.configurations]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-changed-activerecord-base-configurations-result-to-an-object"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-changed-activerecord-base-configurations-result-to-an-object.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-changed-activerecord-base-configurations-result-to-an-object</id>
      <published>2019-03-19T00:00:00.000Z</published>
      <updated>2019-03-19T00:00:00.000Z</updated>
      <author>
        <name>Amit Choudhary</name>
        <uri>https://www.bigbinary.com/blog/authors/amit</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-changed-activerecord-base-configurations-result-to-an-object.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Rails 6 changed ActiveRecord::Base.configurations result to an object instead of a hash]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-changed-activerecord-base-configurations-result-to-an-object"><![CDATA[<p>Rails 6 changed the return value of
<a href="https://github.com/rails/rails/pull/33637">ActiveRecord::Base.configurations</a>
to an object of <code>ActiveRecord::DatabaseConfigurations</code>. Before Rails 6,
<a href="https://api.rubyonrails.org/v5.2.2/classes/ActiveRecord/Core.html#method-c-configurations">ActiveRecord::Base.configurations</a>
returned a hash with all the database configurations. We can call <code>to_h</code> on the
object of <code>ActiveRecord::DatabaseConfigurations</code> to get a hash.</p>
<p>A method named <a href="https://github.com/rails/rails/pull/33637">configs_for</a> has also
been added on to fetch configurations for a particular environment.</p>
<h4>Rails 5.2</h4>
<pre><code class="language-ruby">&gt;&gt; ActiveRecord::Base.configurations

=&gt; {&quot;development&quot;=&gt;{&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/development.sqlite3&quot;}, &quot;test&quot;=&gt;{&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/test.sqlite3&quot;}, &quot;production&quot;=&gt;{&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/production.sqlite3&quot;}}
</code></pre>
<h4>Rails 6.0.0.beta2</h4>
<pre><code class="language-ruby">&gt;&gt; ActiveRecord::Base.configurations

=&gt; #&lt;ActiveRecord::DatabaseConfigurations:0x00007fc18274f9f0 @configurations=[#&lt;ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fc18274f680 @env_name=&quot;development&quot;, @spec_name=&quot;primary&quot;, @config={&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/development.sqlite3&quot;}&gt;, #&lt;ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fc18274f608 @env_name=&quot;test&quot;, @spec_name=&quot;primary&quot;, @config={&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/test.sqlite3&quot;}&gt;, #&lt;ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fc18274f590 @env_name=&quot;production&quot;, @spec_name=&quot;primary&quot;, @config={&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/production.sqlite3&quot;}&gt;]&gt;

&gt;&gt; ActiveRecord::Base.configurations.to_h

=&gt; {&quot;development&quot;=&gt;{&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/development.sqlite3&quot;}, &quot;test&quot;=&gt;{&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/test.sqlite3&quot;}, &quot;production&quot;=&gt;{&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/production.sqlite3&quot;}}

&gt;&gt; ActiveRecord::Base.configurations['development']

=&gt; {&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/development.sqlite3&quot;}

&gt;&gt; ActiveRecord::Base.configurations.configs_for(env_name: &quot;development&quot;)

=&gt; [#&lt;ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fc18274f680 @env_name=&quot;development&quot;, @spec_name=&quot;primary&quot;, @config={&quot;adapter&quot;=&gt;&quot;sqlite3&quot;, &quot;pool&quot;=&gt;5, &quot;timeout&quot;=&gt;5000, &quot;database&quot;=&gt;&quot;db/development.sqlite3&quot;}&gt;]
</code></pre>
<p>Here is the relevant <a href="https://github.com/rails/rails/pull/33637">pull request</a>.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Rails 6 shows unpermitted params in logs in color]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/rails-6-shows-unpermitted-params-in-logs-in-color"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-shows-unpermitted-params-in-logs-in-color.png"/>
      <id>https://www.bigbinary.com/blog/rails-6-shows-unpermitted-params-in-logs-in-color</id>
      <published>2019-03-18T00:00:00.000Z</published>
      <updated>2019-03-18T00:00:00.000Z</updated>
      <author>
        <name>Prathamesh Sonpatki</name>
        <uri>https://www.bigbinary.com/blog/authors/prathamesh</uri>
      </author>
      <category term="Rails 6"/>
      <category term="Rails"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/rails-6-shows-unpermitted-params-in-logs-in-color.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[The unpermitted params are shown in red color for better visibility]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/rails-6-shows-unpermitted-params-in-logs-in-color"><![CDATA[<p>Strong parameters allow us to control the user input in our Rails app. In
development environment the unpermitted parameters are shown in the log as
follows.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-shows-unpermitted-params-in-logs-in-color/before.png" alt="Unpermitted params before Rails 6"></p>
<p>It is easy to miss this message in the flurry of other messages.</p>
<p>Rails 6 has added a change to
<a href="https://github.com/rails/rails/pull/34617">show these params in red color</a> for
better visibility.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2019/rails-6-shows-unpermitted-params-in-logs-in-color/after.png" alt="Unpermitted params after Rails 6"></p>
]]></content>
    </entry>
</feed>