Rails migrations cleanup / redo - ruby-on-rails

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

Related

Rails 4: Re-Migrating all Migrations to Schema

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.

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!

Adding/Updating column in a Model using RubyMine

I'm working on a web app that basically interacts with a db table through a form. Recently I had to make some changes which resulted in me adding another column to the db table. I'm using RubyMine for developing and can't figure out how to update the model so that it contains the new column. I've added it inside the model as so:
class Student < ActiveRecord::Base
attr_accessible :f_name, :floor_pref, :l_name, :is_active
validates_presence_of :f_name, :floor_pref, :l_name
end
I've also added it inside the schema.rb:
ActiveRecord::Schema.define(:version => 20130620140537) do
create_table "students", :force => true do |t|
t.string "f_name"
t.string "l_name"
t.string "floor_pref"
t.boolean "is_active"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
And also inside the migrate as so:
class CreateStudents < ActiveRecord::Migration
def change
create_table :students do |t|
t.string :f_name
t.string :l_name
t.string :floor_pref
t.boolean :is_active
t.timestamps
end
end
end
Problem is when I run the rails console and look up my model object it doesn't show the new column that I have added (:is_active). It only shows the old columns:
>> Student
Loading development environment (Rails 3.2.13)
Switch to inspect mode.
Student(id: integer, f_name: string, l_name: string, floor_pref: string, created_at: datetime, updated_at: datetime)
What am I missing?
What you should do know, is to delete all changes you have added to model app/models/Student.rb and to db/schema.rb
Then you should go to your terminal/console and type
$ rails g migration add_column_name_to_student column_name:type
This command will create new file in db/migrate/ folder.
$ rake db:migrate
After updating your database schema with rake db:migrate. Go to your app/models/Student.rb and add new column_name into attr_accessible, if you want to setup this value by form.
This whole procedure has nothing to do with your IDE.
Here are some other resources, where you can get information how to add new column to models.
Generate Rails Migrations That Automagically Add Your Change
Rails 3: How to add a new field to an existing database table
You should definitely avoid adding new columns the way you did that. It's messy and makes your code difficult to maintain.
This is not the correct way to add a new column to your table. You want to open your console and run the following command your after is rails g migration add_column_name_to_table column_name:type then run a bundle exec rake rake db:migrate. Its not good to just shove things in.
Ex: If I want to add the postedon column to posts table, then:
rails g migration AddPostedOnToPosts posted_on:date
This will add column in your migration file automatically.

rails model default value

Here is my model migration
class CreateSwimmingClassschedules < ActiveRecord::Migration
def change
create_table :swimming_classschedules do |t|
t.integer :slot_id
t.integer :coach_id
t.integer :level_id , :default => 1
t.string :note
t.timestamps
end
end
end
I expect after I call
Swimming::Classchedule.create(:coach_id=>8)
It will generate a default level_id in table. But somehow it didn't work. I'm in the dev environment using SQLite.
I added
:default => 1
after I ran
rake db:migrate
Does it matter?
Something I am missing?
Adding that line after you have run your migrations will not make the change.
Your syntax is correct but you will need to run a migration with that addition. Consider making a separate migration file like this:
class ChangeLevelId < ActiveRecord::Migration
def change
change_column :swimming_classschedules, :level_id, :integer, :default => 1
end
end
If you added :default => 1 AFTER you did a rake db:migrate, you will need to do a rake db:rollback and do a remigration of your database. That should do the trick.
Is it Classchedule or Classschedule ?
When I have a problem with my database, I recreate it :
rake db:drop
rake db:create
rake db:migrate

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