Let's say I have a migration that creates a table 'pages' , this is my migration:
class CreatePages < ActiveRecord::Migration
def up
create_table :pages do |t|
t.string "name" , :limit => 50
t.integer "permalink"
t.integer "position"
t.timestamps
end
end
def down
drop_table :pages
end
end
and that I've created the appropriate migration file X_create_pages.rb and ran it(the table is created in the database).
Now after a few days I realize the structure isn't complete and I need to add another column to my pages table .
What is the best practice , do I create a new migration file with add_column method or do I just change the current migration file's up method -e.g just add my columns to the up method (and then move down a version and then up again - so to run the up method?)
The practice should be you create a new migration to add the new column. This becomes the simplest and risk free path. Of course, we can talk about unseen circumstances!
Updating original migration files should not be used after application is released to production; at least this is what the practice should be. But, this also depends on applications, if you don't have a table that is referenced elsewhere then backing up the data, adding the column and restoring the data is also a possibility which is enabled by this approach of directly modifying the original migration file and rolling down that version and migrating up that version again.
While you are on development, the choice I guess is yours. You could choose either!
Once a migration has been checked into source control it shouldn't be changed.
Modifying a migration on your development environment providing it hasn't been checked into source control is perfectly fine.
Once a migration has been checked in it may have been run by your team mates on their development environment or even been deployed and run in production.
Changing previously committed migrations is going to make you very unpopular in your team very quickly as team mates struggle to understand why their database schema is different from yours but all the migrations have been run.
Related
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.
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.
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).
As you will see, I'm pretty new to Rails.
I am trying to follow section 3.3.2 in the RailsGuides on Active Record Associations and it says there that when defining a many to many relationship, besides adding the has_and_belongs_to_many directive to the model, you "need to explicitly create the joining table".
It then gives an example of the content of the migration file:
class CreateAssembliesPartsJoinTable < ActiveRecord::Migration
def change
create_table :assemblies_parts, id: false do |t|
t.integer :assembly_id
t.integer :part_id
end
end
end
My question is: what name should I give to that file? I see that the files generated by the rails g ... command are all in the ..db\migrate folder and have a kind of timestamp at the beginning of the file. Can I use any name? I'm afraid to test and mess up the whole thing. I'm used to MS-SQL and being able to see the tables, add/modify columns, etc.
Side question: there are a few files already there, from previous migrations. How does rails know which ones were already run? And what about running them afterwards when deploying to, say, Heroku?
You can give any name to your migrations. Preferably something self explanatory like create_table_something. You can generate a migration by doing
rails generate migration create_assemblies_parts_joins_table
This will generate a file like below in db/migrate folder
<timestamp>_create_assemblies_parts_joins_table
Rails keeps track of already run migrations in scheme_migrations table. It stores the timestamp of all the migrations that are already run
UPDATE:
You can change the table name to whatever you want in the migration file. Table will be created with the name you give in the following line
create_table :assemblies_parts, id: false do |t|
assemblies_parts will be the table name.
You should not build the file from scratch yourself. As #Vimsha has already said - you can run a rails migration to create a join table migration for you.
The rails standard naming for a join table is to take the two names of the models you are joining, and write them in alphabetical order and pluralised.
eg if your models are "user" and "post", it would be "posts_users", but if it were "post" and "comment" it would be "comments_posts"
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.