I have a model called Article. This model has attribute called duration which is a string. The duration can be morning, afternoon, evening and night.
For example, article object looks like this:
#<Article id: 1, created_at: "2015-09-22 08:00:08", updated_at: "2015-09-22 08:00:08", duration: "morning">
Since the duration has similar properties, I create a base class called duration and the inherited classes as morning, afternoon, evening and night.
In a duration there can be many articles. But a single article can have only one duration. So, I have has_many
and belongs_to
association:
app/model/duration.rb
class Duration < ActiveRecord::Base
has_many :articles
end
app/model/article.rb
class Article < ActiveRecord::Base
belongs_to :duration
end
Other inherited classes are:
app/model/duration/morning.rb
class Morning < Duration
end
and so on for afternoon.rb
, evening.rb
and night.rb
.
I already have the migration to create durations table. To add the field type
to duration, I have a migration called add_type_to_duration.rb
AddTypeToDuration < ActiveRecord::Migration
def change
add_column :durations, :type, :string
end
end
I have another migration file called add_duration_ref_to_articles.rb
to add reference
class AddDurationRefToArticles < ActiveRecord::Migration
def change
add_reference :articles, :duration, index:true
end
end
I have another migration to create the new durations in add_initial_durations.rb
class AddInitialDurations < ActiveRecord::Migration
def change
Morning.create
Afternoon.create
Evening.create
Night.create
end
end
Now I want to update the old data to adapt according to new migrations. So, I have another migration called update_articles_to_have_duration.rb
class UpdateArticlesToHaveDuration < ActiveRecord::Migration
def change
morning = Duration.find_by_type("Morning")
Article.where(duration: "morning").find_each do |article|
article.update!(duration_id: morning.id)
end
end
end
Now when I run the migrations all the articles, that had duration = morning
, now have duration_id = nil
. However, when I run the last migration again with rake db:migrate:redo step:1
, then articles have correct duration_id. I think somehow the migration is not run properly. However, I don't get any error while running them. Can anyone please let me know what am I doing wrong here?
Thanks for the help.
As you've said that duration_id
is set properly when running the migration second time, the only reason why it's not working on the first go might be that the migrations are not running sequentially as you've shown.
Migration files have timestamps on them and they run oldest first when you do rake db:migrate
.
See the timestamps of the migration file to ensure that they're ordered as you want them.
❯ rake db:migrate:status
database: ~/blog/db/development.sqlite3
Status Migration ID Migration Name
--------------------------------------------------
up 20150907015616 Create articles
down 20150907031746 Create comments
down 20150909034614 Devise create users
You can use above command to see the Migration Id and copy it to run the migrations one after another to verify my assumption with following command:
❯ bin/rake db:migrate VERSION=20150907015616 VERSION=20150907031746 VERSION=20150909034614
You'll have to re-order(better to delete and recreate) the migration files or transpose its contents if the migration files do not follow the chronological order of timestamps.