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
Related
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.
My environemnt:
Ruby 2.2.1
Rails 4.2.4
mysql2 0.3.18 gem
Rails 4.2 introduced add_foreign_key. I am trying to use it so when a search_operation is deleted, the countries that belong to it are deleted from the countries table.
In my models/country.rb, I have:
class Country < ActiveRecord::Base
belongs_to :search_operation
end
In my models/search_operation.rb, I have:
class SearchOperation < ActiveRecord::Base
has_many :countries
end
In my create_countries migration, I have:
class CreateCountries < ActiveRecord::Migration
def change
create_table :countries do |t|
t.string :abbreviation
t.string :status
t.integer :search_operation_id
t.timestamps null: false
end
add_foreign_key :countries, :search_operations, on_delete: :cascade
end
end
In my search_operations migration, I have:
class CreateSearchOperations < ActiveRecord::Migration
def change
create_table :search_operations do |t|
t.string :text
t.string :status
t.timestamps null: false
end
end
end
When I run rake db:migrate, here's what I get:
== 20151010195957 CreateCountries: migrating ==================================
-- create_table(:countries)
-> 0.0064s
-- add_foreign_key(:countries, :search_operations, {:on_delete=>:cascade})
rake aborted!
StandardError: An error has occurred, all later migrations canceled:
Mysql2::Error: Can't create table 'tracker.#sql-463_8f' (errno: 150): ALTER TABLE `countries` ADD CONSTRAINT `fk_rails_c9a545f88d`
FOREIGN KEY (`search_operation_id`)
REFERENCES `search_operations` (`id`)
ON DELETE CASCADE/home/trackur/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:305:in `query'
I believe I am using the proper syntax here. Any ideas?
Solution:
Make sure the migration order is: create search_operations table first, followed by other tables that use its id as a foreign key. I guess ActiveRecord is going to follow the chronological order of when the migration files were created.
Make sure you create the search_operations table before the countries table.
If you set a foreign key the referenced table has to exist.
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)
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
My application seems to work in development, but not when I migrate to Heroku. I generate a Location model:
20140526153201_create_locations.rb
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.string :address
t.float :latitude
t.float :longitude
t.timestamps
end
end
end
I then add a column to a previously migrated model, Organization, of the type Location.
20140526162916_add_location_to_organization.rb
class AddLocationToOrganization < ActiveRecord::Migration
def change
add_column :organizations, :geo_location, :location
end
end
After I push to heroku and run heroku run rake db:migrate:
Migrating to AddLocationToOrganization: migrating =============
PG::Error: ERROR: type "location" does not exist
LINE 1: ...TER TABLE "organizations" ADD COLUMN "geo_location" location
I assume it is because I am trying to use a data type before it exists, but I don't know how to do that. The ordering seems to be logical to me. Any help appreciated!