Rails Migration Successful, But Not Showing up in Model? - ruby-on-rails

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.

Related

ActiveRecord::UnknownAttributeError when adding passive column

I'm trying to run this migration, and the goal is to not have any server downtime while adding new columns. Since these columns have no relationships to other tables, exist in the code, or are required, I assumed this would be possible. But, after running the migration I observed UnknownAttributeError's being thrown when instantiating a new instance of the model.
The error:
Controller/existing_table/some_method::ActiveRecord::UnknownAttributeError
/code/app/models/existing_table.rb:40:in `new’
The line from the error:
e = ExistingTable.new(existing_table.attributes.except("id"))
The migration:
class AddTestFieldToExistingTable < ActiveRecord::Migration
def change
add_column :existing_table, :test_field, :integer
end
end
When I go to recreate the issue by opening up a console and executing lines similar as above, I don't get the error. My guess is that there is some attributes cached and we do need to have downtime while running these "passive" migrations.
I wonder if the 'existing_table' is still in memory, doesn't have the 'test_field' attribute, and when creating a new instance of ExistingTable it doesn't know how to assign the field. Since I cannot recreate it without starting a new instance, I would be guessing on an alternative solution of re-writing the ExistingTable constructor.
Is there a way to avoid restarting the rails instance or re-writing this code? Am I on the right track?
I tried to replicate your doubt, and I did not get the error, besides, everything worked as expected.
I am using Rails 7.0.1
First, I started puma:
rails s -b 0.0.0.0
Then create the migration:
rails g migration AddPassiveToGiro passive:boolean
The migration looks like this:
class AddPassiveToGiro < ActiveRecord::Migration[7.0]
def change
add_column :giros, :passive, :boolean
end
end
On rails console I created a new record:
Giro.create giro: 'delete me', passive: true
Then I modify the view where I list those records (using haml)
.list-item-description
= giro.passive.blank? ? 'not passive' : 'is passive'
And everything worked fine, no errors.
Rails load the tables' columns only once when the Rails server is started.
Depending on your setup and how you run your migration at deployment it might be possible that the server or at least one server instance started before the migration was done. Then that server instance will not see the newly added column until the next server restart.
To be safe you need to make sure that the migration ran successfully before you deploy the code changes using that change. Depending on your server setup that might mean that you need two different deployments: One with the migration and then later another with the code changes.

Running rails migration moves indexes around in schema

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.

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).

ruby migration rolled back but get error when run migration again

This is the error I get when running a migration in a RoR application:
PG::Error: ERROR: column "bulk_bill" of relation "questionnaires" already exists
A little background:
I rolled back a migration so that I could change the default setting for a column.
Once I ran the migration again I got the error above.
I can see in the postgresql table in development that the column does exist. I have a data in the tables and in the bulk_bill column it has it's default set to false.
What are the recommended steps I need to take so that I so the migration can be run successfully.
I am a beginner in ruby and find the ruby documentation still a little hard to follow.
def up
add_column :questionnaires, :bulk_bill, :boolean, :default => false
end
def down
remove_column :pnp_questionnaires, :bulk_bill
end
In your up method you're creating column on questionaries table, and in your down method you are removing it from pnp_questionaries. Remove column does not raise an excepton if table doesn't exists, hence you have your problem.
Simplest solution:
Comment out add_column from up.
Run migrations (yes, run empty migration).
Fix your down method to remove questionaries table.
Rollback migration.
Uncomment your up method.
UPDATE:
My bad - point 3 was to be 'remove column from questionaries', not 'remove table'.
You need to rerun the migration which created the table (hopefuly you didn't alter it in a meantime). Go to the given migration, comment out down method body, and run rake db:migrate:redo VERSION=xxxxxxx where xxxxxx is the timestamp in this migration filename.

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.

Resources