Rails 4: Re-Migrating all Migrations to Schema - ruby-on-rails

I am currently developing an Rails 4 app and over the last few months I collected a lot of unique migration files, which reverse their own changes, etc.
Since I have no problem to reset the db at this stage of development, I thought I could might clean up this mess a bit.Is there a way of redoing all migration files, while also allowing to delete certain migration-files and to expand others?
I appreciate each answer!
Example (Edit)
I have two migration files:
20160911071103_create_items.rb
20160918085621_add_cached_votes_to_items.rb
Both are already migrated.<
1st file before
class CreateItems < ActiveRecord::Migration
def change
create_table :items do |t|
t.integer :user_id
t.timestamps null: false
end
end
end
My goal is to include the added column by the second file directly in the first file and deleting the second.
1st file after
class CreateItems < ActiveRecord::Migration
def change
create_table :items do |t|
t.integer :user_id
t.integer :cached_votes
t.timestamps null: false
end
end
end

You need to run
rake db:migrate:down VERSION=20160918085621
rake db:migrate:down VERSION=20160911071103
You can now check the migration status by rake db:migrate:status and you should expect to get migration status as follows:
down 20160911071103
down 20160918085621
Now, you can remove the migration file 20160918085621_add_cached_votes_to_items.rb
& edit the migration file 20160911071103_create_items.rb as you need.
And, finally run:
rake db:migrate:up VERSION=20160911071103

As you are saying you it's on development only so you can change the migration files.
NOTE: It is not recommended to edit your migration but as it's not deployed anywhere so you can do it.
20160911071103_create_items.rb
class CreateItems < ActiveRecord::Migration
def change
create_table :items do |t|
t.integer :user_id
t.timestamps null: false
end
end
end
20160918085621_add_cached_votes_to_items.rb
class AddCachedVotesToItems < ActiveRecord::Migration
def change
add_column :items, :cached_votes, :integer
end
end
Modify your first migration and remember to delete second migration.
20160911071103_create_items.rb (Migration 1 + Migration 2)
class CreateItems < ActiveRecord::Migration
def change
create_table :items do |t|
t.integer :user_id
t.integer :cached_votes
t.timestamps null: false
end
end
end
And then Drop and Migrate again
rake db:drop # Drop the db
rake db:setup # Create and migrate the db

if you have a working schema.rb file. you can just generate a migration file
bundle exec rails generate migration CreateItemsNew
Then fill the codeblock create_table "items" from your working schema.rb to this newly generated migration file. Then do a bulk search for all the migrations in your db/migrate that changes the table items and delete those files. This way you'll have a single migration file for a table in your db.

Related

Can't migrate to heroku (Ruby on Rails tutorial [Michael Hartl] chaper 10)

I am working through chapter 10 of the Hartl book. In the conclusion of this chapter, we reset the heroku database and then migrate. However when I run:
heroku run rails db:migrate
I get an error:
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedColumn: ERROR: column "password_digest_string" of relation "users" does not exist
: ALTER TABLE "users" DROP "password_digest_string"
Earlier in the tutorial, I removed a column called password_digest_string because it was named incorrectly and I didn't need it yet. It seems like rails is trying to delete the column again even though it isn't there anymore. I deleted the migration file that removed this column but it still is trying to drop it. What's also odd is that I've migrated the database several times since dropping that column and never had this issue until I reset it. Any suggestions?
EDIT:
here is my schema file:
ActiveRecord::Schema.define(version: 20170121224748) do
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.boolean "admin", default: false
t.index ["email"], name: "index_users_on_email", unique: true
end
end
EDIT:
And my migrations in time-stamp order.
..._create_users.rb
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
..._add_index_to_users_email.rb
class AddIndexToUsersEmail < ActiveRecord::Migration[5.0]
def change
add_index :users, :email, unique: true
end
end
..._add_password_digest_to_users.rb
class AddPasswordDigestToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :password_digest, :string
end
end
..._remove_columns.rb
class RemoveColumns < ActiveRecord::Migration[5.0]
def self.up
remove_column :users, :password_digest_string
end
end
..._add_remember_digest_to_users.rb
class AddRememberDigestToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :remember_digest, :string
end
end
..._add_admin_to_users.rb
class AddAdminToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :admin, :boolean, default: false
end
end
It looks to me that the AddPasswordDigestToUsers migration initially looked like this (probably you misspelled):
class AddPasswordDigestToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :password_digest_string
end
end
Then you realized the column should be just password_digest. So you manually edited the migration file to what it looks now, rolled back, created the next migration which is RemoveColumns and then ran migration.
Now when you the migrations from the beginning, there will be no error if you are using sqlite3 (which is what you use for dev environment) due to the way column removal is handled in sqlite. But there will be an error if you use Postgres.
What you should have done
Instead of what you did, you should have just created a migration to change the column name, like this:
class RenamePasswordDigestStringColumn < ActiveRecord::Migration[5.0]
def self.up
rename_column :users, :password_digest_string, :password_string
end
end
What you can do now
To get past the problem without doing many changes now, you can just delete the RemoveColumns migration (and commit, push... etc that). That would be OK and I don't think it will harm your production or development environments.
$> heroku pg:reset DATABASE will make the db:migrate on heroku clean again

Rails migration schema issue

In my rails App I have three models/tables in the database (users, registrants, events). I was setting up some Capybara/RSpec tests when I ran into an issue saying it could not find the events table.
Now the events model has been working fine, I've been able to create events, go into the rails console and query things such as Events.all or Events.find(1). What is confusing me is my schema. My schema has
create_table "registrations", force: true do |t|
t.string "first_name"
...
end
create_table "users", force: true do |t|
t.string "email", default: "", null: false
...
end
But there is no reference to the events table. It's been some time since I generated the model for Events but here is the migration:
class CreateEvents < ActiveRecord::Migration
def change
create_table(:events) do |t|
t.string :name
t.string :location
t.timestamps
end
end
end
I have ran commands such as rake db:reset and rake db:migrate to make sure all my migrations are current. Any ideas why the events table is not in the schema?
UPDATE:
So I've deleted the DB and Schema and began migrating each migration one at a time. The events table is there when I run the migration to create it, but after I run the following command the table disappears from the schema:
class AddingAssociationsToEventsUserModels < ActiveRecord::Migration
def change
add_column :events, :belongs_to, :user, index: true
end
end
Here is the migration being run:
rake db:migrate:redo VERSION=20150518132834
== 20150518132834 AddingAssociationsToEventsUserModels: migrating =============
-- add_column(:events, :belongs_to, :user, {:index=>true})
-> 0.0006s
== 20150518132834 AddingAssociationsToEventsUserModels: migrated (0.0006s) ====
That's because test database and development database are not matched.
Run:
RAILS_ENV=test rake db:drop && rake db:create && rake db:migrate
or
RAILS_ENV=test rake db:test:prepare
or
RAILS_ENV=test rake db:reset
Any of the above should work.
Ok so the issue was a mistake in my migration file. Here is what I changed my migration to:
class AddingAssociationsToEventsUserModels < ActiveRecord::Migration
def change
add_reference :events, :user, index: true
end
end
Now the events table is in my Schema and the test can find the table and is passing!

Why directly changing a migrate file does not change the schema file?

My current migrate file is
class CreateMovies < ActiveRecord::Migration
def up
create_table :movies, :force => true do |t|
t.string :title
t.string :rating
t.text :description
t.datetime :release_date
# Add fields that let Rails automatically keep track
# of when movies are added or modified:
t.timestamps
end
end
def down
drop_table :movies
end
end
I try to change release_date type to integer. So I directly change the file to
class CreateMovies < ActiveRecord::Migration
def up
create_table :movies, :force => true do |t|
t.string :title
t.string :rating
t.text :description
t.integer :release_date
# Add fields that let Rails automatically keep track
# of when movies are added or modified:
t.timestamps
end
end
def down
drop_table :movies
end
end
Please pay attention, the release_date type has been changed. But after I run
bundle exec rake db:migrate
It still produce the same schema file as before. I am so confused.
It's probably because you've already run your migration. So before you want to change it, you should rollback it first:
bundle exec rake db:rollback
then you should modify it and run again:
bundle exec rake db:migrate
As an alternative to dropping and upping the migration, you could make a new migration to change the column type.
class ChangeMoviesReleaseTypeToInteger < ActiveRecord::Migration
def up
change_column :movies, :release_date, :integer
end
def down
change_column :movies, :release_date, :datetime
end
end
Just as a side note, release_date is a confusing name for an integer field - most people would expect it to be a datetime as you had originally.
down will remove the table
rake db:migrate:down VERSION=file_name(exclude extension)
up will create with new changes
rake db:migrate:up VERSION=file_name(exclude extension)

Rails migrations cleanup / redo

So, say I have 10 models that have been evolving over the course of 100 migration files. Is there some sort of utility that could look my schema and build 10 'clean' migration files?
migration:
class CreateFoos < ActiveRecord::Migration
def change
create_table :foos do |t|
t.belongs_to :bar
t.string :baz
t.integer :qux, default: 0
end
add_index :foos, :bar_id
end
end
schema:
ActiveRecord::Schema.define(:version => 20140610225017) do
create_table "foos", :force => true do |t|
t.integer "bar_id"
t.string "baz"
t.integer "qux", :default => 0
end
add_index "foos", ["bar_id"], :name => "index_foos_on_bar_id"
end
I just feel like... if it knows how to go from the migration to the schema, then vice versa would be easy. Does this sound stupid?
I find you can delete your migrations after they have all been applied to all the databases, development through production. If you want to populate a new development or production database from scratch you can either (a) backup production and restore to the new database, or (b) load from the schema.rb file using rake db:schema:load.
If you really want the migrations for some documentation or clarity, create a new schema rails g migration schema2014. After the migration has been applied to production, delete all the old migrations files and copy schema.rb into the new migration.
If you don't care about the actual data and you're dealing with a new installation where you want to just create the DB structure using the schema.rb, you should use rake db:schema:load.
More details:
rake db:schema:load vs. migrations
Generate a migration file from schema.rb

Duplicate column name error when running migration

Whenever I run a migration in my Rails app, I get an error from SQLite3:
SQLite3::SQLException: duplicate column name: photo_file_name: ALTER TABLE "users" ADD "photo_file_name" varchar(255)
I already have a "Add Photo to User" migration. Here it is:
class AddAttachmentPhotoToUsers < ActiveRecord::Migration
def self.up
change_table :users do |t|
t.has_attached_file :photo
end
end
def self.down
drop_attached_file :users, :photo
end
end
And here is the user migration:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :title
t.string :department
t.text :skills
t.boolean :available
t.timestamps
end
end
end
I'm a bit confused by it because it's telling me there is a duplicate column name "photo_file_name" but that I need to add it to the Users table? That doesn't make sense. Shouldn't I need to remove it?
Let me know if you need any other details about my app.
That happens if you migrations are not in sync with the database schema. This could happen if
you modified the database schema "by hand"
you changed a migration file being run
migrations have not been updated in the schema_migrations table
If you are not relying on the data in the database, a rake db:reset would re-run all migrations from scratch. Otherwise you have to make the conflicting migration recognized as already-run by adding to the schema_migrations table.
See RailsGuides of migrations as well.
I've also solved this problem by logging into the heroku database, and then dropping only the offending column. I think this is a less-destructive solution.
drop the development schema from your workbench
run rails db:create db:migrate

Resources