<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Phan Quang Lam</title>
    <description>The latest articles on DEV Community by Phan Quang Lam (@lamphanqg).</description>
    <link>https://dev.to/lamphanqg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F326100%2F7bfe5dd0-90d7-40a4-8f5b-3c9ca388a451.jpg</url>
      <title>DEV Community: Phan Quang Lam</title>
      <link>https://dev.to/lamphanqg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lamphanqg"/>
    <language>en</language>
    <item>
      <title>About db:migrate and schema.rb version</title>
      <dc:creator>Phan Quang Lam</dc:creator>
      <pubDate>Sat, 29 Jan 2022 13:04:16 +0000</pubDate>
      <link>https://dev.to/lamphanqg/about-dbmigrate-and-schemarb-version-4fa4</link>
      <guid>https://dev.to/lamphanqg/about-dbmigrate-and-schemarb-version-4fa4</guid>
      <description>&lt;p&gt;This week, I had an argument (a healthy one 😗) at work about the version in Rails' schema.rb.&lt;/p&gt;

&lt;p&gt;In my feature branch, I added a migration file with version older than the latest version in main branch, so when I run &lt;code&gt;db:migrate&lt;/code&gt;, the version in schema.rb is not updated. My colleage insists that anytime you commit a new migration file, the schema.rb version needs to be updated too, or &lt;code&gt;rails db:migrate&lt;/code&gt; will not run that migration file in other environments. However, as I understand &lt;code&gt;rails db:migrate&lt;/code&gt; does not care about the version in schema.rb, it only compares the version list in &lt;code&gt;db/migrate&lt;/code&gt; folder and version list in &lt;code&gt;schema_migrations&lt;/code&gt; table, and run any migration that has not been run.&lt;/p&gt;

&lt;p&gt;We didn't have much time to talk about it considering that it's not really important, so I just change the migration file name, run &lt;code&gt;db:migrate&lt;/code&gt; again in my local to update the version and commit it. Now, out of curiosity, I want to look more into this matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rails' official guide
&lt;/h2&gt;

&lt;p&gt;The first place to look is always &lt;a href="https://guides.rubyonrails.org/active_record_migrations.html#what-are-schema-files-for-questionmark" rel="noopener noreferrer"&gt;the official guide&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By default, Rails generates db/schema.rb which attempts to capture the current state of your database schema.&lt;/p&gt;

&lt;p&gt;It tends to be faster and less error prone to create a new instance of your application's database by loading the schema file via bin/rails db:schema:load than it is to replay the entire migration history. Old migrations may fail to apply correctly if those migrations use changing external dependencies or rely on application code which evolves separately from your migrations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And &lt;a href="https://guides.rubyonrails.org/active_record_migrations.html#running-migrations" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that running the db:migrate command also invokes the db:schema:dump command, which will update your db/schema.rb file to match the structure of your database.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's just like what I see about schema.rb: just a file to store current table structure of your database. &lt;code&gt;db:migrate&lt;/code&gt; will generate or modify it, but it should not affect how &lt;code&gt;db:migrate&lt;/code&gt; run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stackoverflow
&lt;/h2&gt;

&lt;p&gt;If answers and replies in &lt;a href="https://stackoverflow.com/questions/2979059/rails-is-the-version-number-in-schema-rb-used-for-anything" rel="noopener noreferrer"&gt;this question&lt;/a&gt; are correct, it seems like &lt;code&gt;db:migrate&lt;/code&gt; used to assume that all migrations up to the version in schema.rb are applied, and will not run new migration files with older version. However, that has been already changed, and now &lt;code&gt;db:migrate&lt;/code&gt; does not decide which file should be run based on that version anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source code
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Truth can be found in one place: the code.&lt;br&gt;
ー Robert C. Martin, Clean Code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OK, enough for documents and answers. Now I need to see the truth. After searching through activerecord's source code, I confirmed my thoght: &lt;code&gt;db:migrate&lt;/code&gt; will check &lt;code&gt;schema_migrations&lt;/code&gt; table to determine which migration files have been run and which not. Then it will run all files of versions which are not in &lt;code&gt;schema_migrations&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rails/rails/blob/main/activerecord/lib/active_record/migration.rb#L1307" rel="noopener noreferrer"&gt;Source 1&lt;/a&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;migrated&lt;/span&gt;
  &lt;span class="vi"&gt;@migrated_versions&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;load_migrated&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_migrated&lt;/span&gt;
  &lt;span class="vi"&gt;@migrated_versions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Set&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="vi"&gt;@schema_migration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_versions&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:to_i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/rails/rails/blob/main/activerecord/lib/active_record/migration.rb#L1343" rel="noopener noreferrer"&gt;Source 2&lt;/a&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ran?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;migrated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/rails/rails/blob/main/activerecord/lib/active_record/migration.rb#L1287" rel="noopener noreferrer"&gt;Source 3&lt;/a&gt;&lt;/p&gt;


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

&lt;p&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;runnable&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;runnable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;up?&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;runnable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ran?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;&lt;br&gt;
    &lt;span class="c1"&gt;# skip the last migration if we're headed down, but not ALL the way down&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;runnable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;runnable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_all&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ran?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Test&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Of course, we cannot have a firm conclusion if we don't test it. So here is how I test it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a migration file with timestamp &lt;code&gt;20220129000000&lt;/code&gt; in branch &lt;code&gt;main&lt;/code&gt; and migrate it and commit schema.rb&lt;/li&gt;
&lt;li&gt;Create a new branch &lt;code&gt;test&lt;/code&gt; from &lt;code&gt;main&lt;/code&gt;, add a migration file with timestamp &lt;code&gt;20220128000000&lt;/code&gt; and migrate it &lt;strong&gt;=&amp;gt; schema.rb version is expected not to change&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Change back to &lt;code&gt;main&lt;/code&gt; branch, drop db and migrate again&lt;/li&gt;
&lt;li&gt;Merge &lt;code&gt;test&lt;/code&gt; into &lt;code&gt;main&lt;/code&gt; and run migrate again &lt;strong&gt;=&amp;gt; although schema.rb version does not change, the migration file &lt;code&gt;20220128000000&lt;/code&gt; is expected to be applied&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;p&gt;After step 2, schema.rb version does not change:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foohpi8oi3y11rp4jebr5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foohpi8oi3y11rp4jebr5.png" alt="step 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After step 3, only the migration file of version &lt;code&gt;20220129000000&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fconjf5uzxhhnn6nc4exm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fconjf5uzxhhnn6nc4exm.png" alt="step 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After step 4, the migration file of verion &lt;code&gt;20220128000000&lt;/code&gt; is applied even when schema.rb version does not change:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2dlbsgqldgcqi7r5mkj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2dlbsgqldgcqi7r5mkj.png" alt="step 4"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Phew... Finally I got something to show my colleage the next time we talk! 🧐&lt;/p&gt;

&lt;p&gt;(Post copied from &lt;a href="https://lamphanqg.github.io/2022/01/29/about-schemarb-version.html" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
  </channel>
</rss>
