Running rails migration moves indexes around in schema - ruby-on-rails

The app in question was originally created as a Rails 4 app, and later upgraded to Rails 5.
I will create a rails migration that might look like this:
class AddPubliclyVisibleToGcodeMacros < ActiveRecord::Migration[5.0]
def change
add_column :gcode_macros, :publicly_visible, :boolean, default: false
end
end
And when I run it, I expect the schema to have a few lines updated, specifically adding t.boolean "publicly_visible", default: false
to the gcode_macros table.
However, running the migration creates a LOT of changes to my schema, mostly just moving indexes from outside a create_table block, into it.
Im quite confused over whats going on here. This isn't something that happened all of a sudden, I've just been working around it for a while now.
Any help would be greatly appreciated!

The answer is that this is just how the schema dumper works in Rails. It takes the schema from the database, absolutely irrelevant from how you created the structure in the first place, whether with migrations or direct sql statements.
So when you create a new migration or change anything in the db a new schema is dumped based on the database.
Edit
I should add that schema.rb is not updated if the db is changed directly with sql statements, that is not through a migration. Only when either
rake db:migrate
or ...
rake db:schema:dump
are run is the schema.rb file updated.

Related

Why isn't my schema.rb file updated?

I recently looked at my schema.rb file and was alarmed to find that certain columns that do exist in my database do not appear, and some tables are missing entirely. The missing columns were added to the database through "def change add_column" migrations, though some columns that were added in that way do appear as expected in schema.rb.
On closer inspection, I realized that schema.rb has not been updated since I created the Users table.
20151019205241_create_users.rb:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps null: false
end
end
end
This has not caused an issue for me in practice, but I thought schema.rb was supposed to be kept automatically updated, and that it would be important to have it updated in order to recreate the database. Can anyone help me figure out why it would not be updating?
One possibility is that it stopped being updated when I switched my database from sqlite3 to postgresql. I don't remember exactly, but I think the timing makes sense.
You can use rake db:schema:dump to re-create the file from the current database structure.
Schema file is independent from the driver so migrating from sqlite3 to PostgreSQL shouldn't matter. Make sure that version for definition in the file is not greater than current the current date. You can also add the whole file to the question's snippet.

Database changes not reflecting after Rake and Migrate commands

I am working very first time on Rails Application. I am using Rails 4. As per tutorials and books I used Rails migrate command to generate initial schema. After that I called rake db:migrate. The message says table created but when I go to db/development.sqlite3 I find no table at all.
Following is the code of Migration File
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.string :title
t.text :summary
t.integer :total_impacts #added later but does not reflect in db
t.integer :current_status #added later but does not reflect in db
t.timestamps
end
end
end
What steps am I missing?
Since I am on early stages of Database I rather called db:schema:load after making changes in schema.rb file.
I guess add_column should work too but not sure.
After reading the comments, I assume that the table was successfully created but that it's only a problem with the :total_impacts and :current_status columns.
If you run a migration once, the database knows that it's already been through it and won't run it again unless specified explicitly (rake db:migrate VERSION=...).
So if you write a migration, run it, then update it and try to run it again, the stuff you've just added (like a new column) won't appear in your database (because the migration has already been run in the database point of view).
If you realize after running the migration that you forgot some things, you have two options:
You can write another migration for the things you want to add/delete and run it. (Easy stuff).
You can rollback the migration (play the down part), edit it and run it again (play the up part). This one can be a bit more tricky depending on when you realize your mistake (has some data related to that migration already been added? etc).

Rails Migration Successful, But Not Showing up in Model?

I can't figure out why my migration worked but doesn't show up in corresponding model...
Ran a migration to add field to a table:
def up
add_column :quick_tests, :trace_route_data, :text, :null => true
end
def down
remove_column :quick_tests, :trace_route_data
end
Looked in schema.rb, and it's there.
Added :trace_route_data to attr_accessible in QuickTest model
Opened up rails console by doing bundle exec rails c, ran QuickTest.new and I can see the :trace_route_data field.
But, when I execute the same QuickTest.new statement when paused in the QuickTestController#show method, the field isn't there.
Why is this field showing up in the rails console but not my actual app??
I suspect something went wrong during the migration such that it never got applied to the database. Rails uses the actual schema in the database to build model objects, so the fact that your model doesn't show the change means the change is almost certainly not in the database (despite being in the schema.rb).
I'd recommend you rollback your migration and run it again in verbose mode. This should either show you the error, or at least show you the SQL being run. In that case, you can run the SQL manually at the db console and see what happens then.

Writing database migration to reverse complex migration

I have a pretty old migration on a legacy app by a friend that contains this snippet:
class MakeChangesToProductionDbToMatchWhatItShouldBe < ActiveRecord::Migration
def self.up
# For some reason ActiveRecord::Base.connection.tables.sort().each blows up
['adjustments',
'accounts',
...## more rows of classes here ###...
'product_types'].each do |table|
t = table.singularize.camelize.constantize.new
if t.attributes.include?('created_at')
change_column( table.to_sym, :created_at, :datetime, :null => false ) rescue puts "#{table} doesnt have created_at"
end
if t.attributes.include?('updated_at')
change_column( table.to_sym, :updated_at, :datetime, :null => false ) rescue puts "#{table} doesnt have updated_at"
end
end
This old migration is now conflicting with a new migration I wrote to remove two of the tables mentioned in this long list, which is now causing any deployment to error upon rake db:migrate.
What's the correct kind of migration or down action to write to address this migration and get db:migrate working again?
There are a few different best practices that can help, but at the end of the day there's no good way to always upgrade a database from an arbitrary point without stepping through the codebase along as you run migrations (speaking of which, why is there not already a rake task to do this?).
Always include a migration-namespaced copy of the models you're working on. Example below.
When building a database from scratch, do not run migrations…use db:schema:load which will re-create the last snapshot of the database.
Don't give your migrations ridiculous and aggression fueled titles like MakeChangesToProductionDbToMatchWhatItShouldBe.
Avoid making assumptions, when writing migrations, about the environment they will be run in. This includes specifying table names, database drivers, environment variables, etc.
Write down actions when you write up actions whenever a down action is feasible. It's usually much easier (especially on esoteric or complex migrations) when the series of transformations is fresh in your head.
For this specific case, there's an argument to be made for declaring “Migration Bankruptcy” — clearing out some or all existing migrations (or refactoring and coalescing into a new one) to achieve the desired database state. When you do this you are no longer backwards compatible so it is not to be taken lightly, but there are times it is the appropriate move.

How do I add a new attribute to a migration in Rails 3?

Here's my story: I had something like this set up a while ago.
create_table(:users) do |t|
t.database_authenticatable :null => false
t.recoverable
t.rememberable
t.trackable
t.integer :total_pageviews
and "total_pageviews" worked fine. I could set it to zero, increment it, multiply it, call it, whatever. but let's say i want to add:
t.integer :total_votes
What do I have to do to configure total_votes as an attribute? Whenever I try to use "total_votes", I get undefined method error. I'm thinking that the answer is something like rake db:migrate or similar.
You should not ever alter existing migrations. If you have checked them in to your version control system and somebody else runs them and then you add a new field to them and commit that change, they will not know to get that change. Then you must tell them and it's a pain in the butt to fix.
If you've not committed it yet then rollback the migration (rake db:rollback), make the necessary modification and re-run it again (rake db:migrate).
But in the Real World, you would create a new migration which adds this field using rails g migration add_total_votes_to_users total_votes:integer.
Rails will interpret this migration name and know what to do with it, generating a migration that contains this line:
add_column :users, :total_votes, :integer
Then when you run this migration it will add this total_votes field to the users table which will make an attribute of the same name for all User objects.
Are you adding this after the migration has been run? So, the users table exists and you want to add a column to it? If so, you need go create a migration like
rails generate migration add_total_votes_to_users
Open it up (just to verify that the table and column are correct). Then run the migration.
If you app is in production, then you should create a new migration. If you app is in pre-production stage, and you have a small development team with good communication, then I recommend you to go ahead and modify the migration and then do
rake db:drop
rake db:create
rake db:migrate
then you can commit the modified migration file and let the rest of you team know that that you have changed a migration file.

Resources