1

Preface

I know I could create a new migration, but I want to know if it is possible to edit an existing one in this way. This is just me learning Rails and trying out new things. There is no production version of this code running.

The issue

I am trying to get my series table in my schema to contain a reference to books, but it is not working.

Initial setup

rails db:migrate:status has me at this state:

Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190330155354  Create articles
   up     20190401004837  Create comments
   up     20190402231737  Create books
   up     20190402233013  Create pages
   up     20190403221445  Create series

And my file 20190402231737_create_books.rb looks like this:

class CreateBooks < ActiveRecord::Migration[5.2]
  def change
    create_table :books do |t|
      t.integer :series_number
      t.integer :year_published

      t.timestamps
    end
  end
end

Steps taken

First I rollback to the migration I want to edit (I have to run the following command 3 times - specifying a version # doesn't seem to work and I am not sure why):

rails db:rollback

Now rails db:migrate:status has me at this state:

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190330155354  Create articles
   up     20190401004837  Create comments
  down    20190402231737  Create books
  down    20190402233013  Create pages
  down    20190403221445  Create series

I added this line to the books migration:

t.references :series, foreign_key: true

Then I run the migrations:

rails db:migrate

Expected result

What I want is for my schema to be generated with this:

  create_table "series", force: :cascade do |t|
    t.string "title"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["series_id"], name: "index_books_on_series_id"
  end

Actual result

The line t.index ["series_id"], name: "index_books_on_series_id" never gets added to the schema.

Taylor Liss
  • 593
  • 4
  • 27
  • Why dont you create new migration? – Martin Apr 04 '19 at 15:06
  • I know I could create a new migration, but I want to know if it is possible to edit an existing one in this way. This is just me learning Rails and trying out new things. There is no production version of this code running. – Taylor Liss Apr 04 '19 at 15:08

2 Answers2

4

You could probably solve this by adding a new index in a new migration.

In general, rolling back migrations to alter them leads to all sorts of problems. What happens with the data in these tables? And so on.

I suggest you make a new migration: rails g migration add_book_reference_on_series

Then edit it like so:

add_reference :series, :book, index: true

I hope this helps.

Best,

ekampp
  • 1,904
  • 18
  • 31
  • I know I could create a new migration, but I want to know if it is possible to edit an existing one in this way. This is just me learning Rails and trying out new things. There is no production version of this code running. – Taylor Liss Apr 04 '19 at 15:09
  • You can't add a series reference to the books' migration because the series table doesn't exist at the point, where you create the books table. – ekampp Apr 04 '19 at 15:10
  • Ah! Ok! That makes sense! I had a feeling that was the case. Is it possible to "reorganize" migrations? Would renaming the migration to make it occur later be a viable technique? – Taylor Liss Apr 04 '19 at 15:13
  • 1
    Yep. If you haven't run them in production, then you can simply rename to rearrange. But be super careful if they have been run on any other computer than yours this will reek havoc with everyone else's data structure. – ekampp Apr 04 '19 at 15:16
  • Awesome! Thanks for the help! I'm accepting your answer as the correct one! – Taylor Liss Apr 04 '19 at 15:18
  • @EmilKampp, you can add the reference if you use the approach below, but it is unsafe, as running migrations, later on, will wreak havoc (as you said). But you can always load schema with the latest changes. – Zalom Apr 04 '19 at 15:40
  • @ZlatkoAlomerovic, you can't add a reference on the books table for the series table, if the series table doesn't exist? – ekampp Apr 07 '19 at 15:27
  • @EmilKampp as I said, it is possible via approach below, as you do not alter later migrations, but only one. The caveat with this is, that running migrations will not work. The proper approach would be to add another migration, as you posted. The only way for the approach from my posting is to load the schema at a later point, and not running migrations, as migrations will be broken (because of a reference to a non-existant table) – Zalom Apr 08 '19 at 11:28
  • 1
    Yeah, I see, what you're saying. It's a viable approach, although not pretty. I read your approach as rolling back to the timestamp, but your only rolling back that single timestamp. – ekampp Apr 09 '19 at 07:22
1

I will cite the text from the original question, from above.

Preface.

I know I could create a new migration, but I want to know if it is possible to edit an existing one in this way. This is just me learning Rails and trying out new things. There is no production version of this code running.

This is the way how to edit an existing migration ...

You can use ->

rails db:migrate:down VERSION=20190402231737

without the need to rollback several times.

Change the migration in question and then again run

rails db:migrate

But this is potentially unsafe if you work in a team and also running all migrations from the beginning in a new environment can have unexpected results, and possibly be broken, as there will be a reference to a non-existent table.

So this should not be done unless you know what you are doing.

Changing Existing Migrations - Rails Guides
Rollback a specific migration - Stackoverflow

Zalom
  • 696
  • 9
  • 18