<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>MaxLapDev</title>
  <subtitle>Ruby, Rails, Tools</subtitle>
  <id>https://maxlap.dev/blog</id>
  <link href="https://maxlap.dev/blog"/>
  <link href="https://maxlap.dev/blog/ruby_rails_feed.xml" rel="self"/>
  <updated>2023-12-10T19:00:00-05:00</updated>
  <author>
    <name>Maxime Lapointe</name>
  </author>
  <entry>
    <title>The lesser known Rails race condition</title>
    <link rel="alternate" href="https://maxlap.dev/blog/2023/12/11/the-lesser-known-rails-race-condition.html"/>
    <id>https://maxlap.dev/blog/2023/12/11/the-lesser-known-rails-race-condition.html</id>
    <published>2023-12-10T19:00:00-05:00</published>
    <updated>2023-12-11T08:27:15-05:00</updated>
    <author>
      <name>Maxime Lapointe</name>
    </author>
    <content type="html">&lt;div class="markdown-body"&gt;&lt;p&gt;Note: This post mentions and gives examples in Rails, but the content is relevant to anyone using databases systems,
regardless of the use cases.&lt;/p&gt;

&lt;p&gt;There are many posts around discussing race conditions in Rails and how to handle/avoid them, but I haven&amp;#39;t seen
one discussion this particular case.&lt;/p&gt;

&lt;p&gt;Simply put, race conditions happen when more than one worker/process/thread interact with the same data and
the order those interactions happen in can give undesirable results.&lt;/p&gt;

&lt;h2 id="classical-race-condition"&gt;Classical race condition&lt;/h2&gt;

&lt;p&gt;The classical example of a race condition is having 2 processes altering the same bank account at the same time.
Depending on the order that operations happen in, some of the alterations might be lost.&lt;/p&gt;

&lt;p&gt;Starting with 100$, if one process does a +10 and another a -15 at the same time. You can end up with each of the
following amounts in the account:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;110 (wrong)&lt;/li&gt;
&lt;li&gt;85 (wrong)&lt;/li&gt;
&lt;li&gt;95 (good)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I won&amp;#39;t delve into this since there are already lots of articles about and how to avoid it in Rails.
&lt;a href="https://www.honeybadger.io/blog/avoid-race-condition-in-rails/"&gt;Here&amp;#39;s one&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="the-lesser-known-race-condition"&gt;The lesser known race condition&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s think about a single writer and a single reader. Reading some of the articles on Rails race conditions, you
could believe everything will be fine.&lt;/p&gt;

&lt;p&gt;Consider the database already contains these two records:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Now if you have a reader doing a report:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:total&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:unpublished&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&amp;#x000A;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;And you have a writer adding some data at the same time:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Here are the possible reports you might get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;{total: 2, published: 1, unpublished: 1}&lt;/li&gt;
&lt;li&gt;{total: 2, published: 1, unpublished: 2}&lt;/li&gt;
&lt;li&gt;{total: 3, published: 1, unpublished: 2}&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of these is incoherent. You can&amp;#39;t have 2 posts total but then have numbers that add up to 3 at the same time.&lt;/p&gt;

&lt;p&gt;This example may feel contrived. It almost always feel like a technicality; the shown result is clearly wrong, but the
database doesn&amp;#39;t end up with wrong data. You can &amp;quot;just&amp;quot; refresh the page the very few times this happens and the
problem will be gone. It&amp;#39;s one of those little glitch that no one can reproduce and no one bothers tracking down
since it doesn&amp;#39;t happen often anyways.&lt;/p&gt;

&lt;p&gt;If something like this is in some kind of nightly report, it&amp;#39;s not so easy to &amp;quot;just&amp;quot; refresh the page.&lt;/p&gt;

&lt;h2 id="but-wait-theres-more"&gt;But wait, there&amp;#39;s more!&lt;/h2&gt;

&lt;p&gt;You might be tempted to think that this only happens when doing multiple queries on a single table, so you are safe
as lon as you query only once per table. If you define the problem as any incoherency caused by the timing, you would
be wrong.&lt;/p&gt;

&lt;p&gt;If the reader does:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# Querying the posts table&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:has_admin_comment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has_admin_comment&lt;/span&gt; &lt;span class="c1"&gt;# an attribute&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# Querying the comments table&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt; &lt;span class="c1"&gt;# Imagine they are rendered in a page&lt;/span&gt;&amp;#x000A;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;And you have a writer adding some data at the same time:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A callback will see the post's has_admin_comment&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# Imagine a call&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;by_admin: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;has_admin_comment: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;There is now the possibility that the report contains a comment by an admin while the &lt;code&gt;has_admin_comment&lt;/code&gt; attribute
says there are no such comments.&lt;/p&gt;

&lt;p&gt;So as soon as you do 2 queries, if any of the data of those two queries is related to the other query, there is a
chance you&amp;#39;ll encounter this. Bummer, I frequently do more than one SQL query in my pages.&lt;/p&gt;

&lt;h2 id="a-solution"&gt;A solution&lt;/h2&gt;

&lt;p&gt;The root of the problem is that we are reading data at different points in time, but we want to treat it as if it was
from a single point in time.&lt;/p&gt;

&lt;p&gt;The only solution I&amp;#39;m aware of (other than doing only one query), is to tell the database: &amp;quot;Ignore all changes from
elsewhere when working on my queries&amp;quot;. Where elsewhere means other processes / transations.&lt;/p&gt;

&lt;p&gt;In PostgreSQL, that can be done with a transaction with the &lt;code&gt;repeatable_read&lt;/code&gt; isolation level. From &lt;a href="https://www.postgresql.org/docs/current/transaction-iso.html"&gt;PostgreSQL&amp;#39;s doc&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Repeatable Read isolation level only sees data committed before the transaction began; it never sees
either uncommitted data or changes committed during transaction execution by concurrent transactions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So going back to our first example, if the reader did this instead:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;isolation: :repeatable_read&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:total&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:unpublished&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&amp;#x000A;  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Then only the 2 valid reports would be possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;{total: 2, published: 1, unpublished: 1}&lt;/li&gt;
&lt;li&gt;{total: 3, published: 1, unpublished: 2}&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: In other database systems (such as MySQL or SQLite), it&amp;#39;s possible that you need a different isolation level
than &lt;code&gt;repeatable_read&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id="when-to-solve-it"&gt;When to solve it?&lt;/h2&gt;

&lt;p&gt;I think the final question is when should you &amp;quot;solve&amp;quot; this problem? When should you run within a repeatable_read
transaction?&lt;/p&gt;

&lt;p&gt;I don&amp;#39;t know... It depends.&lt;/p&gt;

&lt;p&gt;I have never actually tackled this problem in an application-wide manner... yet. So take these suggestions with a
grain of salt.&lt;/p&gt;

&lt;p&gt;Doing more restrictive transactions can have an impact on performance, can add latency, could introduce deadlocks,
could increase the number of transactions that need to be retried. But I&amp;#39;m not sure this is actually a problem in
practice.&lt;/p&gt;

&lt;p&gt;When starting a new application, I would consider wrapping every request in a transaction and calling it a day.
It&amp;#39;s too early to focus on scaling/performance in the beginning. The day you grow enough (if that happens) or
encounter problems caused to this, then you can either disable this for some request or start doing it only for
more critical requests.&lt;/p&gt;

&lt;p&gt;For existing applications, wrapping every request could cause new problems to appear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existing race conditions you didn&amp;#39;t know about might now produce an error. (I think this is good)&lt;/li&gt;
&lt;li&gt;Nested transactions can behave slightly differently.&lt;/li&gt;
&lt;li&gt;Locks will be held longer, possibly resulting in longer latency and deadlocks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So is it worth it to wrap every request for existing application? Your guess is as good as mine. Maybe do it,but progressively?&lt;/p&gt;

&lt;p&gt;One thing to consider about this is that while you can &amp;quot;just&amp;quot; refresh a page, it&amp;#39;s not always so simple.
If you are generating a pdf or generating new data from what you queries, then the glitch isn&amp;#39;t quite so temporary
anymore, is it?&lt;/p&gt;

&lt;p&gt;So at the very least, you probably want to use the &lt;code&gt;repeatable_read&lt;/code&gt; transaction whenever you are generating
something longer lasting than a web page, no matter the consequences.&lt;/p&gt;

&lt;h2 id="code-to-apply-everywhere"&gt;Code to apply %everywhere&lt;/h2&gt;

&lt;p&gt;In my case, for my new application, I&amp;#39;m trying it. It&amp;#39;s barely any code at all.&lt;/p&gt;

&lt;p&gt;Here is a callback on my &lt;code&gt;ApplicationController&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;around_action :wrap_in_transaction&amp;#x000A;def wrap_in_transaction&amp;#x000A;  ActiveRecord::Base.transaction(isolation: :repeatable_read) do&amp;#x000A;    yield&amp;#x000A;  end&amp;#x000A;end&amp;#x000A;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#39;s that simple! Except... It&amp;#39;s likely your tests may fail, because they also start a transaction, with a different
isolation level.&lt;/p&gt;

&lt;p&gt;So add this your your &lt;code&gt;test_helper.rb&lt;/code&gt; / &lt;code&gt;spec_helper.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Tests already use a transaction, this tries to nest with a distinct isolation level, which breaks. So skip&amp;#x000A;ApplicationController.skip_around_action :wrap_in_transaction&amp;#x000A;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="closing-words"&gt;Closing words&lt;/h2&gt;

&lt;p&gt;Hope you learned something useful!&lt;/p&gt;

&lt;p&gt;If you want to play with examples that are similar to the post and demonstrate the effects of the &lt;code&gt;repeatable_read&lt;/code&gt;
transaction, here is a &lt;a href="/blog/2023/12/11/the-lesser-known-rails-race-condition.rb"&gt;self-contained ruby script&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>What makes Ruby's blocks great</title>
    <link rel="alternate" href="https://maxlap.dev/blog/2022/02/10/what-makes-ruby-blocks-great.html"/>
    <id>https://maxlap.dev/blog/2022/02/10/what-makes-ruby-blocks-great.html</id>
    <published>2022-02-09T19:00:00-05:00</published>
    <updated>2024-09-08T14:02:40-04:00</updated>
    <author>
      <name>Maxime Lapointe</name>
    </author>
    <content type="html">&lt;div class="markdown-body"&gt;&lt;p&gt;In Ruby, we often talk about &amp;quot;blocks&amp;quot;. While not unique to Ruby, few mainstream languages
have something I would consider equivalent and, to be frank, I think they&amp;#39;re missing out.&lt;/p&gt;

&lt;p&gt;Just explaining to someone what&amp;#39;s special about them can be tricky. I think many rubyists
use blocks without realizing that they are different from what&amp;#39;s possible in other
mainstream languages.&lt;/p&gt;

&lt;p&gt;This post is an attempt to explain what&amp;#39;s great about blocks without being a verbose
in-depth guide. It&amp;#39;s written with non-rubyists in mind. I hope it can pique your interest.&lt;/p&gt;

&lt;h2 id="anonymous-function-with-a-nicer-syntax"&gt;Anonymous function with a nicer syntax&lt;/h2&gt;

&lt;p&gt;That&amp;#39;s the first thing one may say to describe them, or the first thing that someone
hearing about them will think of, and... that&amp;#39;s a start. The nicer syntax is certainly an
important part of what makes Ruby&amp;#39;s blocks feel great to use, but there is more than just that.&lt;/p&gt;

&lt;p&gt;Compared to anonymous functions, blocks are more powerful and more consistent with other
standard constructs such as &lt;code&gt;for&lt;/code&gt; loops. So much so that they have entirely replaced &lt;code&gt;for&lt;/code&gt; loops
in Ruby; you instead call a method and pass it a block.&lt;/p&gt;

&lt;p&gt;Blocks managed to do that because they have more control over the flow of code than your regular
anonymous functions, giving them as much power as a &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;

&lt;p&gt;To explain what I mean, let&amp;#39;s work with a simple &amp;quot;for each&amp;quot; loop. Here is what a block looks like
in Ruby.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="code-book "&gt;&lt;div class="code-book__left"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;To make it easier for non-rubyists, I&amp;#39;m using a style closer to other languages.&lt;/p&gt;

&lt;p&gt;What we call a &amp;quot;block&amp;quot; goes from &lt;code&gt;do&lt;/code&gt; to &lt;code&gt;end&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Quick code explanation:&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;An Array literal, it &amp;quot;gives&amp;quot; an Array with those 4 values. Same as JavaScript&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;Calls the method &lt;code&gt;each&lt;/code&gt; (on the Array), passing it the block that follows the parentheses&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;The parameters the block accepts: one parameter called &amp;quot;v&amp;quot;.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;The content of the block, what will run when it is called. This prints the value to the console.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Other than the clean syntax for passing the block (&amp;quot;anonymous function&amp;quot;), this is nothing special.
In javascript, this would be:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Another syntax exists, but I think this is more universally recognizable&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;From this common ground, let&amp;#39;s see how using blocks compare to anonymous functions by thinking of loops.&lt;/p&gt;

&lt;h2 id="break"&gt;&lt;code&gt;break&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Most languages with loops allows you to exit early from them. Usually with a &lt;code&gt;break&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;Think of the previous examples, but stopping (like &lt;code&gt;break&lt;/code&gt;) after &lt;code&gt;v == 3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How do you do this with the &lt;code&gt;forEach&lt;/code&gt; method in JavaScript? The simple answer is that you can&amp;#39;t
do it simply. You either switch to an actual &lt;code&gt;for&lt;/code&gt; loop or use exceptions or some other workaround.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;break&lt;/code&gt; cannot be used to exit an anonymous function. But in Ruby, in a block...&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;break&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;&lt;code&gt;break&lt;/code&gt; just works.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;break&lt;/code&gt; exits from the function to which the block was passed (&lt;code&gt;each&lt;/code&gt; in this case), so the block can stop early
just like in regular &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ll talk more about &lt;code&gt;break&lt;/code&gt; in a bit; it can do more, but I want to go over the simpler
cases first.&lt;/p&gt;

&lt;h2 id="return"&gt;&lt;code&gt;return&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;How about returning from a function from within a loop? That&amp;#39;s pretty common.&lt;/p&gt;

&lt;p&gt;You, again, can&amp;#39;t do this using anonymous functions in most languages. The &lt;code&gt;return&lt;/code&gt; keyword
would only return from the anonymous function and its caller would call it again for the
next iterations.&lt;/p&gt;

&lt;p&gt;But it&amp;#39;s easy in Ruby with its blocks:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Just defining a function to return out of&lt;/span&gt;&amp;#x000A;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;    &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&amp;#x000A;      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;&lt;code&gt;return&lt;/code&gt; just works, again!&lt;/p&gt;

&lt;p&gt;When the code reaches the &lt;code&gt;return&lt;/code&gt;, it&amp;#39;s not the block which returns 42, it&amp;#39;s actually
&lt;code&gt;my_func&lt;/code&gt;. &lt;code&gt;return&lt;/code&gt; leaves the block, the call to &lt;code&gt;each&lt;/code&gt;, and returns from &lt;code&gt;my_func&lt;/code&gt;
with the specified value. Just like &lt;code&gt;return&lt;/code&gt; does in actual loops.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;return&lt;/code&gt; can still useful be useful in an anonymous functions. It can return a value to
be used, such as a &lt;code&gt;map&lt;/code&gt; function or it can stop the current iteration to go to the next
one. This is the equivalent of &lt;code&gt;continue&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt;. So let&amp;#39;s move over to these.&lt;/p&gt;

&lt;h2 id="continue-next"&gt;&lt;code&gt;continue&lt;/code&gt; / &lt;code&gt;next&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;In loops, we sometimes want to skip an iteration, just go to the next one. Most languages
will have a &lt;code&gt;continue&lt;/code&gt; or &lt;code&gt;next&lt;/code&gt; keyword that can be used in loops.&lt;/p&gt;

&lt;p&gt;Instead of stopping, let&amp;#39;s skip the iteration where &lt;code&gt;v == 3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As mentioned in the previous section, JavaScript and most other languages can achieve this
in anonymous functions using &lt;code&gt;return&lt;/code&gt;, but they cannot use the standard &lt;code&gt;continue&lt;/code&gt; or &lt;code&gt;next&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;  &lt;span class="p"&gt;}&lt;/span&gt;&amp;#x000A;  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Ruby has &lt;code&gt;next&lt;/code&gt; and it works in blocks exactly as one would expect in a loop.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;next&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Pretty neat.&lt;/p&gt;

&lt;p&gt;This is where the parallels with &lt;code&gt;for&lt;/code&gt; loops end.&lt;/p&gt;

&lt;h2 id="next-42"&gt;&lt;code&gt;next 42&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Blocks are used for more than just replacing a simple &lt;code&gt;for&lt;/code&gt; loop. Let&amp;#39;s switch to using
&lt;code&gt;map&lt;/code&gt; for our examples. For those unfamiliar, &lt;code&gt;map&lt;/code&gt; is a &lt;code&gt;for&lt;/code&gt; loop which also saves a
return value for each iteration in an array and returns that array.&lt;/p&gt;

&lt;p&gt;As an example, &lt;code&gt;squares&lt;/code&gt; gets set to an array of the square (2nd power) of each number.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;squares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# Ruby detail: the `next` is optional for the last expression, the `next` is implicit&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# Leaving it in for clarity&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;&lt;code&gt;next&lt;/code&gt; can receive a value. It&amp;#39;s what it will &amp;quot;return&amp;quot; to the method that called the block
(&lt;code&gt;map&lt;/code&gt; in this case). It really is just a &lt;code&gt;return&lt;/code&gt; that stays at the block&amp;#39;s level.&lt;/p&gt;

&lt;p&gt;In JavaScript with an anonymous function, you would use &lt;code&gt;return&lt;/code&gt; with a value.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;squares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;h2 id="break-42"&gt;&lt;code&gt;break 42&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;In Ruby, &lt;code&gt;break&lt;/code&gt; can also receive a value. &lt;em&gt;Break&lt;/em&gt;-ing news, right? :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# We add a secret override code... it's an example ok! suggest a better one in the comments&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;squares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;666&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;666&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;In addition to breaking out of the function that received the block (the &lt;code&gt;map&lt;/code&gt; in this example),
the function will return the value given to &lt;code&gt;break&lt;/code&gt;. So in the above example, &lt;code&gt;squares&lt;/code&gt; will
be set to &lt;code&gt;[-666]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Honestly, this is rarely used. Again, no equivalent here in JavaScript and most other languages.&lt;/p&gt;

&lt;p&gt;These were the main things that make blocks in Ruby more than just anonymous functions.
Still with me? Here is a little wrap up.&lt;/p&gt;

&lt;h2 id="building-an-intuition"&gt;Building an intuition&lt;/h2&gt;

&lt;p&gt;With the right perspective, blocks&amp;#39; behaviors are quite intuitive.&lt;/p&gt;

&lt;p&gt;When dealing with loops, you have 3 nested constructs interacting: a wrapping function, a loop
statement and the loop&amp;#39;s body; and you have 3 keywords to choose where the flow of the code goes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;return&lt;/code&gt; returns from the wrapping function&lt;/li&gt;
&lt;li&gt;&lt;code&gt;break&lt;/code&gt; leaves the loop statement&lt;/li&gt;
&lt;li&gt;&lt;code&gt;next&lt;/code&gt; / &lt;code&gt;continue&lt;/code&gt; leaves loop&amp;#39;s body&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When dealing with blocks or anonymous functions, it&amp;#39;s instead 3 nested &amp;quot;functions&amp;quot; that are
interacting: a wrapping function, a called function and an anonymous functions (or block).&lt;/p&gt;

&lt;p&gt;Ruby&amp;#39;s blocks, let you use the same 3 keywords to choose where the flow of the code goes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;return&lt;/code&gt; returns from the wrapping function (ex: &lt;code&gt;my_func&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;break&lt;/code&gt; returns from the called function (ex: &lt;code&gt;each&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;next&lt;/code&gt; returns from the block&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quite consistent. But since we are talking about functions instead of statements (loop),
return values are also involved. Allowing both &lt;code&gt;break&lt;/code&gt; and &lt;code&gt;next&lt;/code&gt; to provide a return value fits
well in that model and is quite useful. The 3 keywords are basically &lt;code&gt;return&lt;/code&gt;, but they have different targets.&lt;/p&gt;

&lt;h2 id="more-than-just-loops"&gt;More than just loops&lt;/h2&gt;

&lt;p&gt;I&amp;#39;ve been focusing on looping structures because those are common and simple to understand,
but blocks are used for lots of things.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_file.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"w"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'y'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'z'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# It is automatically closed when leaving the block&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# Including if you use return/break/next within&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="n"&gt;thr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# Do stuff in your thread&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="no"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# Code that will be interrupted if it takes more than 5 seconds&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="c1"&gt;# (on a Hash, often called a Map or a Dictionary in different languages)&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# The block is only called if "my_key" is not in the hash.&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"my_key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# generate default value, maybe set it in the hash&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="c1"&gt;# Ok, another loop because it's cute&lt;/span&gt;&amp;#x000A;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# This block gets called 5 times, with `i` going from 0 to 4&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;h2 id="tool-making"&gt;Tool making&lt;/h2&gt;

&lt;p&gt;Programming is all about making tools from other tools. To me, blocks are a very neat
one that fit seamlessly in the Ruby language and handle many roles. They really feel
like a generalization of anonymous functions and I wish more mainstream languages would
have them.&lt;/p&gt;

&lt;h2 id="try-ruby-out"&gt;Try Ruby out&lt;/h2&gt;

&lt;p&gt;You can try Ruby from your browser at &lt;a href="https://try.ruby-lang.org/"&gt;https://try.ruby-lang.org/&lt;/a&gt;. There is a small
Ruby lesson built into the site, but it may feel too simple for more advanced programmers.
Anyhow, it will let you type some Ruby and see the result.&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>You should avoid `includes` in Rails</title>
    <link rel="alternate" href="https://maxlap.dev/blog/2021/02/15/you-should-avoid-includes-in-rails.html"/>
    <id>https://maxlap.dev/blog/2021/02/15/you-should-avoid-includes-in-rails.html</id>
    <published>2021-02-14T19:00:00-05:00</published>
    <updated>2023-10-12T13:13:23-04:00</updated>
    <author>
      <name>Maxime Lapointe</name>
    </author>
    <content type="html">&lt;div class="markdown-body"&gt;&lt;p&gt;&lt;code&gt;includes&lt;/code&gt; is the recommended way to load associations of your records eagerly in Rails. In fact, the
&lt;a href="https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations"&gt;Ruby on Rails guide for eager loading&lt;/a&gt;
only mentions &lt;code&gt;includes&lt;/code&gt;. However, there are other ways, and I want to argue that you should
avoid &lt;code&gt;includes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;includes&lt;/code&gt; makes it easy to introduce an odd bug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preload&lt;/code&gt; takes the same arguments as &lt;code&gt;includes&lt;/code&gt;, but can&amp;#39;t introduce the bug&lt;/li&gt;
&lt;li&gt;When needed, &lt;code&gt;eager_load&lt;/code&gt; also takes the same arguments, can introduce the bug, but makes it explicit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What bug? Let&amp;#39;s show the introduction of an unexpected bug:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="code-book "&gt;&lt;div class="code-book__left"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;Say you have these records:&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;&amp;#x000A;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;content: &lt;/span&gt;&lt;span class="s1"&gt;'hello'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;content: &lt;/span&gt;&lt;span class="s1"&gt;'world'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;You want posts that have at least one comment marked as spam.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# distinct because joins can make duplicates&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# I dislike using joins for this.&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;distinct&lt;/span&gt;&amp;#x000A;            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;comments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left code-book__left--has-after"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;How many comments in this array?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right code-book__right--has-after"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left code-book__left--after"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;&lt;button class="spoiler-toggler btn btn-xs btn-default"&gt;Answer&lt;/button&gt;&lt;/p&gt;

&lt;div class="spoiler-target"&gt;&lt;p&gt;2, nothing special there.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right code-book__right--after"&gt;&lt;/div&gt;&lt;div class="code-book__left code-book__left--has-after"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;You will need to display the comments of the posts, so you &lt;code&gt;includes&lt;/code&gt; them.&lt;/p&gt;

&lt;p&gt;How many comments are in the array?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right code-book__right--has-after"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left code-book__left--after"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;&lt;button class="spoiler-toggler btn btn-xs btn-default"&gt;Answer&lt;/button&gt;&lt;/p&gt;

&lt;div class="spoiler-target"&gt;&lt;p&gt;Only 1, the one with `spam = true`&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right code-book__right--after"&gt;&lt;/div&gt;&lt;div class="code-book__left code-book__left--has-after"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;What&amp;#39;s the &lt;code&gt;count&lt;/code&gt;?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right code-book__right--has-after"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left code-book__left--after"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;&lt;button class="spoiler-toggler btn btn-xs btn-default"&gt;Answer&lt;/button&gt;&lt;/p&gt;

&lt;div class="spoiler-target"&gt;Back to 2! &lt;span class="with-tooltip" data-tippy-content="`count` does a new query, ignoring what is already loaded."&gt;&amp;nbsp;?&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right code-book__right--after"&gt;&lt;/div&gt;&lt;div class="code-book__left code-book__left--has-after"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;What about &lt;code&gt;size&lt;/code&gt;?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right code-book__right--has-after"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="code-book__left code-book__left--after"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;&lt;button class="spoiler-toggler btn btn-xs btn-default"&gt;Answer&lt;/button&gt;&lt;/p&gt;

&lt;div class="spoiler-target"&gt;Back to 1! &lt;span class="with-tooltip" data-tippy-content="`size` just returns the size of what is already loaded."&gt;&amp;nbsp;?&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right code-book__right--after"&gt;&lt;/div&gt;&lt;div class="code-book__left"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;To be clear, the &lt;code&gt;joins&lt;/code&gt; isn&amp;#39;t needed for this to happen.&lt;/p&gt;

&lt;p&gt;It was just to show a progression.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="highlight code-book__right"&gt;&lt;div class="code-book__right-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;comments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&amp;#x000A;    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# =&amp;gt; 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Personally, I find that unexpected.&lt;/p&gt;

&lt;p&gt;Imagine if the &lt;code&gt;post&lt;/code&gt; is passed to a view or a helper, which uses the &lt;code&gt;comments&lt;/code&gt;. It
would only print the comments that matched the condition. Now if you try to debug from that helper,
you would see that &lt;code&gt;post.comments&lt;/code&gt; only has 1 comment.&lt;/p&gt;

&lt;p&gt;Hopefully, you know that this is how &lt;code&gt;includes&lt;/code&gt; (and &lt;code&gt;eager_load&lt;/code&gt;, see below) behaves, so you may look
up where the &lt;code&gt;post&lt;/code&gt; comes from and figure it out. Good luck otherwise.&lt;/p&gt;

&lt;p&gt;This is considered &lt;a href="https://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-eager-loaded-associations"&gt;a feature&lt;/a&gt;.
The consequences of doing conditions on eager loaded association are not in the guide, but they
are in the &lt;a href="https://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-eager-loaded-associations"&gt;middle of this section of the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I sometimes see this called &amp;quot;conditional eager loading&amp;quot;, and the bug is doing it accidentally.&lt;/p&gt;

&lt;p&gt;I consider the whole feature a maintenance burden. At least the guide doesn&amp;#39;t recommend using it.&lt;/p&gt;

&lt;h2 id="tl-dr-my-recommendations"&gt;TL;DR: my recommendations&lt;/h2&gt;

&lt;p&gt;Things will get more technical in the next sections, so my condensed and straightforward recommendations are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For new code, if you are only doing eager loading, use &lt;code&gt;preload&lt;/code&gt; instead of &lt;code&gt;includes&lt;/code&gt;. It does the same eager
loading as &lt;code&gt;includes&lt;/code&gt;, and takes the same arguments, but it ignores the conditions in the query. With it, things
work as expected:&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;distinct&lt;/span&gt;&amp;#x000A;            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;comments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 2&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 2&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; 2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;ul&gt;
&lt;li&gt;If you need to order by an association, then &lt;code&gt;eager_load&lt;/code&gt; is basically the only simple way to do so.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you need a condition (a &lt;code&gt;where&lt;/code&gt;) which uses an association, avoid &lt;code&gt;includes&lt;/code&gt;, &lt;code&gt;joins&lt;/code&gt; and &lt;code&gt;eager_load&lt;/code&gt;.&lt;br&gt;
Instead, I recommend my gem: &lt;a href="https://github.com/MaxLap/activerecord_where_assoc"&gt;activerecord_where_assoc&lt;/a&gt;.
Here&amp;#39;s an &lt;a href="https://github.com/MaxLap/activerecord_where_assoc/blob/master/INTRODUCTION.md"&gt;introduction to it&lt;/a&gt;.&lt;br&gt;
It&amp;#39;s made for this purpose, and will support many more use cases, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recursive associations (parent/child)&lt;/li&gt;
&lt;li&gt;Polymorphic belongs_to&lt;/li&gt;
&lt;li&gt;Negative conditions (ex: posts without comments marked as spam)&lt;/li&gt;
&lt;li&gt;Multiple conditions on different records of the same association&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternatively, there&amp;#39;s another gem for this: &lt;a href="https://github.com/EugZol/where_exists"&gt;where_exists&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Same as before, posts that have at least one comment marked as spam&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where_assoc_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If &lt;code&gt;includes&lt;/code&gt; seem to work somewhere that &lt;code&gt;preload&lt;/code&gt; doesn&amp;#39;t, you&amp;#39;re probably doing a condition
on an association or ordering by an association. See the previous points for this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For existing code, you can&amp;#39;t mindlessly change all &lt;code&gt;includes&lt;/code&gt; to &lt;code&gt;preload&lt;/code&gt;, because some of it may rely on
&lt;code&gt;includes&lt;/code&gt; adding a &lt;code&gt;JOIN&lt;/code&gt; to the query (the &lt;code&gt;eager_load&lt;/code&gt; way), which happens when the query refers to the table of the
included associations. So while it would be better to change everything to &lt;code&gt;preload&lt;/code&gt; and sometimes &lt;code&gt;eager_load&lt;/code&gt;, every such change must
be tested.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you see an &lt;code&gt;includes&lt;/code&gt; with a &lt;code&gt;references&lt;/code&gt;, then that&amp;#39;s just a call to &lt;code&gt;eager_load&lt;/code&gt;. At this point, just use
&lt;code&gt;eager_load&lt;/code&gt; to make your code shorter.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So don&amp;#39;t risk &lt;code&gt;includes&lt;/code&gt; doing the wrong thing. &lt;code&gt;preload&lt;/code&gt; means simple eager loading without the booby trap;
you should use it. Treat &lt;code&gt;eager_load&lt;/code&gt; as a warning sign that this could be doing conditional eager loading and
be careful around it.&lt;/p&gt;

&lt;h2 id="down-the-rabbit-hole"&gt;Down the rabbit hole&lt;/h2&gt;

&lt;p&gt;If you want to understand why I make those recommendations, we&amp;#39;ll have to get technical...&lt;/p&gt;

&lt;p&gt;Eager loading means loading associations of multiple records before they are needed. This is done to reduce
the number of queries executed, making execution faster.&lt;/p&gt;

&lt;p&gt;There are actually 3 methods for eager loading in Rails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;preload&lt;/code&gt;: Executes one extra query per association being eager loaded. Same as &lt;code&gt;includes&lt;/code&gt; usually does.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eager_load&lt;/code&gt;: Adds &lt;code&gt;JOIN&lt;/code&gt; to the SQL query and load the association without doing an extra query. This also
enables adding conditions on the table, which is the cause of the conditional eager loading bug from the
introduction.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;includes&lt;/code&gt;: Picks between &lt;code&gt;preload&lt;/code&gt; and &lt;code&gt;eager_load&lt;/code&gt; based on if there is a reference, in the query, to the
table of an association that was passed to &lt;code&gt;includes&lt;/code&gt;. This can be from &lt;code&gt;where&lt;/code&gt; or from &lt;code&gt;joins&lt;/code&gt;.&lt;br&gt;
You may also specify an association with &lt;code&gt;references&lt;/code&gt; to force the &lt;code&gt;eager_load&lt;/code&gt; path, which is needed when
your conditions are specified with a &lt;code&gt;String&lt;/code&gt; instead of a &lt;code&gt;Hash&lt;/code&gt; (which, again, causes conditional eager loading).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So out of the 3 methods, only one of them cannot trigger conditional eager loading: &lt;code&gt;preload&lt;/code&gt;. It only does
full eager loading, always the same way.&lt;/p&gt;

&lt;h2 id="when-is-eager_load-needed"&gt;When is &lt;code&gt;eager_load&lt;/code&gt; needed?&lt;/h2&gt;

&lt;p&gt;The main reason to use &lt;code&gt;eager_load&lt;/code&gt;, that I have no alternative for, is ordering by an association&amp;#39;s field.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Ordering posts by created_at of last comment&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eager_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"comments.created_at DESC"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Maybe some use it to reduce the number of queries when they do eager loading. I don&amp;#39;t think it really saves much,
and there is a risk of slowing things down by making queries that are &lt;span class="with-tooltip" data-tippy-content="If you use `eager_load` with multiple `has_many`, the rows get multiplied, and you end up with a massive amount of data that your DB is returning to your web server."&gt;heavier&lt;/span&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Some may use it to actually do conditional eager loading. I still heavily disagree with that use case.
&lt;button class="spoiler-toggler btn btn-xs btn-aside btn-inline spoiler-toggler--always-displayed"&gt;Anecdote&lt;/button&gt;&lt;/p&gt;

&lt;div class="spoiler-target"&gt;&lt;div class="markdown-body"&gt;&lt;p&gt;I&amp;#39;ve had to edit code that used this &amp;quot;feature&amp;quot; once...&lt;/p&gt;

&lt;p&gt;You look at a method and it looks wrong; it can&amp;#39;t be doing what it should be doing. It&amp;#39;s using every
&lt;code&gt;project.users&lt;/code&gt;, not just those we want! When I did an interactive console there (&lt;code&gt;binding.pry&lt;/code&gt;
or &lt;code&gt;byebug&lt;/code&gt;), I saw that users were missing from &lt;code&gt;project.users&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since I knew of this &amp;quot;feature&amp;quot;, I started looking and, as expected, a condition on an &lt;code&gt;includes&lt;/code&gt; was found...
3 method calls away from where the association was used, not a single comment to explain what is going on anywhere.&lt;/p&gt;

&lt;p&gt;You should avoid code that looks wrong. Code that uses conditional eager loading looks wrong. In our case
the overall module was already something that we wanted to rewrite from scratch, so this was just another reason
to do so.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Other than ordering, I mostly see &lt;code&gt;eager_load&lt;/code&gt; used to do a condition (a &lt;code&gt;where&lt;/code&gt;) which uses an association. Let&amp;#39;s dig into these.&lt;/p&gt;

&lt;h2 id="where-on-an-association-with-eager_load"&gt;&lt;code&gt;where&lt;/code&gt; on an association with &lt;code&gt;eager_load&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;It&amp;#39;s a somewhat frequent need and there are many questions about this on stack overflow.&lt;/p&gt;

&lt;p&gt;The bug from the introduction, accidentally doing conditional eager loading, started with such a need: &amp;quot;I want the
posts that have comments marked as spam&amp;quot;.&lt;/p&gt;

&lt;p&gt;You may see a recommendation to use &lt;code&gt;includes&lt;/code&gt;, and then have a condition on its table. This actually
uses the &lt;code&gt;eager_load&lt;/code&gt; path.&lt;/p&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Please stop doing this :(&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;comments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# which is equivalent to this; don't do this either&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eager_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;comments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Again, this does conditional eager loading, which isn&amp;#39;t what we asked for.&lt;/p&gt;

&lt;p&gt;To be clear, the &lt;code&gt;where&lt;/code&gt; on an association with &lt;code&gt;includes&lt;/code&gt; / &lt;code&gt;eager_load&lt;/code&gt; &lt;strong&gt;can&lt;/strong&gt; be safe. But only &lt;strong&gt;if&lt;/strong&gt;
the association is a &lt;code&gt;belongs_to&lt;/code&gt;. When it is, there are only 2 possibilities: either load the
record and the associated &lt;code&gt;belongs_to&lt;/code&gt; records, or don&amp;#39;t load either. No conditional eager loading is possible.&lt;/p&gt;

&lt;p&gt;But even when it&amp;#39;s safe, there are risks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;includes&lt;/code&gt; / &lt;code&gt;eager_load&lt;/code&gt; increases the chance for a mistake, where you or someone else &lt;em&gt;just&lt;/em&gt;
add another association to the existing eager loading call.&lt;/li&gt;
&lt;li&gt;Every time a reader sees &lt;code&gt;includes&lt;/code&gt; / &lt;code&gt;eager_load&lt;/code&gt;, he may wonder if it is safe, or if there could be
accidental conditional eager loading.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;And as a tool, this isn&amp;#39;t so great:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you don&amp;#39;t need the associated records, then eager loading them is wasteful.&lt;/li&gt;
&lt;li&gt;Doesn&amp;#39;t handle recursive associations (ex: parent/children)&lt;/li&gt;
&lt;li&gt;&lt;span class="with-tooltip" data-tippy-content="&amp;lt;div class=&amp;quot;markdown-body&amp;quot;&amp;gt;&amp;lt;p&amp;gt;A query for posts with &amp;amp;quot;a comment marked as spam&amp;amp;quot; and &amp;amp;quot;a comment by an admin&amp;amp;quot; will actually only return posts with &amp;amp;quot;a comment that is both marked as spam and made by an admin&amp;amp;quot; instead it being possible to be two different comments.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;So doing this kind of query in &amp;lt;code&amp;gt;scope&amp;lt;/code&amp;gt; means they can interact incorrectly.&amp;lt;/p&amp;gt; &amp;lt;/div&amp;gt; "&gt;Doesn&amp;#39;t compose well&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Looks potentially wrong when you know of the conditional eager loading &amp;quot;feature&amp;quot;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="where-on-an-association-with-joins"&gt;&lt;code&gt;where&lt;/code&gt; on an association with &lt;code&gt;joins&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The next option is to use &lt;code&gt;joins&lt;/code&gt;. It also has downsides.&lt;/p&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Please stop doing this :(&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;comments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# and stop doing this&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;joins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;distinct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;comments: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;Using &lt;code&gt;joins&lt;/code&gt; like this is better than &lt;code&gt;includes&lt;/code&gt; / &lt;code&gt;eager_load&lt;/code&gt; since at least, there is no risk of conditionally
loading an association. But there are still problems with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doesn&amp;#39;t handle recursive associations (ex: parent/children)&lt;/li&gt;
&lt;li&gt;Requires a &lt;code&gt;distinct&lt;/code&gt; to avoid duplicated records when used with &lt;code&gt;has_many&lt;/code&gt; associations.&lt;br&gt;
This can be unexpected if you&amp;#39;re doing a more complex query than j ust fetching records.&lt;/li&gt;
&lt;li&gt;&lt;span class="with-tooltip" data-tippy-content="&amp;lt;div class=&amp;quot;markdown-body&amp;quot;&amp;gt;&amp;lt;p&amp;gt;A query for posts with &amp;amp;quot;a comment marked as spam&amp;amp;quot; and &amp;amp;quot;a comment by an admin&amp;amp;quot; will actually only return posts with &amp;amp;quot;a comment that is both marked as spam and made by an admin&amp;amp;quot; instead it being possible to be two different comments.&amp;lt;/p&amp;gt; &amp;lt;p&amp;gt;So doing this kind of query in &amp;lt;code&amp;gt;scope&amp;lt;/code&amp;gt; means they can interact incorrectly and change more things than just adding a condition (it adds a &amp;lt;code&amp;gt;distinct&amp;lt;/code&amp;gt;).&amp;lt;/p&amp;gt; &amp;lt;/div&amp;gt; "&gt;Doesn&amp;#39;t compose well&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="where-on-an-association-with-arel"&gt;&lt;code&gt;where&lt;/code&gt; on an association with Arel&lt;/h2&gt;

&lt;p&gt;Truth is, this need for a &lt;code&gt;where&lt;/code&gt; on an association isn&amp;#39;t something that ActiveRecord supports well. So
leaving the ActiveRecord only solutions, you can do an actual &lt;code&gt;EXISTS&lt;/code&gt; query with Arel. &lt;code&gt;EXISTS&lt;/code&gt; is
the SQL tool that is meant to do this type of condition, not &lt;code&gt;JOIN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# An OK way, but error prone&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"posts.id = comments.post_id"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;arel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;This composes much better with other tools because all it does is add a single &lt;code&gt;WHERE&lt;/code&gt; clause to the query.
It works as you would expect with &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt; and with other conditions on the same association.&lt;/p&gt;

&lt;p&gt;But there still are new downsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must manually write condition to link the &lt;code&gt;posts&lt;/code&gt; to the &lt;code&gt;comments&lt;/code&gt;. It&amp;#39;s easy to forget it, and I&amp;#39;ve seen
StackOverflow answers that forgot to do so.&lt;br&gt;
You won&amp;#39;t get any error for forgetting, your query will just be wrong, which may not even be obvious if all
you have is a little test data.
Bonus: This can get extra tedious for polymorphic associations, where you also need to this check: &lt;code&gt;foos.owner_type = #{Bar.base_class.name}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If a condition was given when defining the association, you must also manually rewrite it.&lt;/li&gt;
&lt;li&gt;Only the models are named in the code, not the association of interest. This makes the intent less clear, especially
when non-trivial associations exist.&lt;/li&gt;
&lt;li&gt;Extra work to handle recursive associations (ex: parent/children)&lt;/li&gt;
&lt;li&gt;Quite a bit longer to write, and this is a short example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other than writing the whole condition manually, which would have all the problems of the Arel way, but be
more verbose and more error-prone, I think we&amp;#39;re out of built-in ways.&lt;/p&gt;

&lt;h2 id="where-on-an-association-with-activerecord_where_assoc"&gt;&lt;code&gt;where&lt;/code&gt; on an association with activerecord_where_assoc&lt;/h2&gt;

&lt;p&gt;What I recommend for conditions based on associations is a gem I made just for this purpose:
&lt;a href="https://github.com/MaxLap/activerecord_where_assoc"&gt;activerecord_where_assoc&lt;/a&gt;. It looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight lone-highlighted-code"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Please consider doing this:&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where_assoc_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;spam: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# Or using a scope such as is_spam:&lt;/span&gt;&amp;#x000A;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where_assoc_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_spam&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;p&gt;The query it generates is the same as the Arel example, with the same benefits and more.
See for yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It just adds a single &lt;code&gt;where&lt;/code&gt; condition, so it composes well and works with &lt;code&gt;or&lt;/code&gt; and with
other conditions on the same association.&lt;/li&gt;
&lt;li&gt;Handles recursive associations automatically (ex: parent/children)&lt;/li&gt;
&lt;li&gt;Handles polymorphic belongs_to (&lt;code&gt;includes&lt;/code&gt; and &lt;code&gt;joins&lt;/code&gt; would simply refuse)&lt;/li&gt;
&lt;li&gt;Easy to do a &lt;code&gt;NOT&lt;/code&gt; of the condition (I.E.: where no comment is marked as spam)
with &lt;code&gt;where_assoc_not_exists&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Composes with other such queries, even on the same association, even with negations&lt;/li&gt;
&lt;li&gt;Unlike Arel, this uses the association&amp;#39;s name, so the intent is clearer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if you need to do this kind of condition, here are some references for my gem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/MaxLap/activerecord_where_assoc/blob/master/INTRODUCTION.md"&gt;Introduction to activerecord_where_assoc&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MaxLap/activerecord_where_assoc/blob/master/ALTERNATIVES_PROBLEMS.md"&gt;The problems of the other ways of doing such conditions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MaxLap/activerecord_where_assoc/blob/master/EXAMPLES.md"&gt;Multiple example usages&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There&amp;#39;s simply no way I could find to use builtin tools to have this query be clear, succinct and not booby trapped.
Either live with the booby traps, write your own methods to do this cleanly, or use one of the gems written for this purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mine: &lt;a href="https://github.com/MaxLap/activerecord_where_assoc"&gt;activerecord_where_assoc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/EugZol/where_exists"&gt;where_exists&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seriously, try any of them, it&amp;#39;s liberating how simple this once complex task becomes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-body"&gt;&lt;h2 id="but-includes-is-everywhere"&gt;But &lt;code&gt;includes&lt;/code&gt; is everywhere&lt;/h2&gt;

&lt;p&gt;It is! Let&amp;#39;s explore the reasons I can think of.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;includes&lt;/code&gt; is the &amp;quot;smart&amp;quot; function out of the 3, it will pick the &amp;quot;right&amp;quot; strategy when needed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Marketing-wise, this sounds like a good thing... Until you learn that the alternate path, &lt;code&gt;eager_load&lt;/code&gt;, is
not always what you want and it can cause bugs due to conditional eager loading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For a long time, &lt;code&gt;includes&lt;/code&gt; (and &lt;code&gt;eager_load&lt;/code&gt;) were the only way to do a &lt;code&gt;LEFT JOIN&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The method &lt;code&gt;left_joins&lt;/code&gt; was added in Rails 5.0. Before that, if you wanted one, you had to either do
&lt;code&gt;includes&lt;/code&gt; / &lt;code&gt;eager_load&lt;/code&gt;, or write the whole &amp;quot;LEFT JOIN&amp;quot; yourself like this: &lt;code&gt;joins(&amp;quot;LEFT JOIN&amp;#x000A;comments ON comments.post_id = posts.id&amp;quot;)&lt;/code&gt;. The &lt;code&gt;includes&lt;/code&gt; shortcut was often suggested.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;includes&lt;/code&gt; has always been recommended, so most are familiar with it, and most recommend it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything is against &lt;code&gt;preload&lt;/code&gt;, even it&amp;#39;s &lt;a href="https://apidock.com/rails/ActiveRecord/QueryMethods/preload"&gt;documentation&lt;/a&gt; makes &lt;code&gt;preload&lt;/code&gt;
sound like an &lt;span class="with-tooltip" data-tippy-content="As of writing this post it only says: &amp;quot;Allows preloading of args, in the same way that #includes does&amp;quot;, with one trivial example."&gt;alias for &lt;code&gt;includes&lt;/code&gt;&lt;/span&gt;, and the Rails guide only mentions &lt;code&gt;includes&lt;/code&gt; for eager loading data.&lt;/p&gt;

&lt;p&gt;I think not enough people were both harmed by &lt;code&gt;includes&lt;/code&gt; and aware that you can just specify &lt;code&gt;preload&lt;/code&gt; and &lt;code&gt;eager_load&lt;/code&gt; for that knowledge to spread.&lt;/p&gt;

&lt;h2 id="recap"&gt;Recap&lt;/h2&gt;

&lt;p&gt;Conditional eager loading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;includes&lt;/code&gt; and &lt;code&gt;eager_load&lt;/code&gt; can accidentally eager load only part of an association, a good source of bugs.&lt;/li&gt;
&lt;li&gt;Doing conditional eager loading voluntarily can be maintenance burden&lt;/li&gt;
&lt;li&gt;If you do want conditional eager loading, using &lt;code&gt;eager_load&lt;/code&gt; makes it a bit more obvious.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conditions based on associations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;includes&lt;/code&gt; and &lt;code&gt;eager_load&lt;/code&gt; for conditions based on associations can do conditional eager loading at
the same time, you will get bitten by the bugs it can causes.&lt;/li&gt;
&lt;li&gt;if you don&amp;#39;t need to load the association, eager loading it is wasteful&lt;/li&gt;
&lt;li&gt;Using specialized gems to do conditions based on association is safer, clearer and easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Order based on association:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;includes&lt;/code&gt; and &lt;code&gt;eager_load&lt;/code&gt; are the only simple way.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;eager_load&lt;/code&gt; is explicit about the use case, and you don&amp;#39;t need to also call &lt;code&gt;references&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regular old eager loading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just use &lt;code&gt;preload&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to run the examples from this post, here is a &lt;a href="/blog/2021/02/15/you-should-avoid-includes-in-rails.rb"&gt;self-contained ruby script&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
</feed>
