I was changing the name of my previous followers model. I decided to go back to it's original name but was having errors. I decided to use the Drop_table method to solve the issue but further issue pursist. I deleted any file related to followers and did rake db:schema:load which resulted in no errors. But whenever I try to do
rails g model Follower follower_id:integer followed_id:integer
and edit it to
def change
create_table :followers do |t|
t.integer :follower_id
t.integer :followed_id
t.timestamps
end
add_index :followers, :follower_id
add_index :followers, :leader_id
add_index :followers, [:follower_id, :leader_id], unique: true
end
Then I execute rake db:migrate and I get the following. Anyone has an idea how I'll be able to fix this issue without having to start from the beginning? any help is appreciated. Thank you.
== 20150910203914 CreateFollowers: migrating ==================================
-- create_table(:followers)
-> 0.0011s
-- add_index(:followers, :follower_id)
-> 0.0004s
-- add_index(:followers, :leader_id)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table followers has no column named leader_id: CREATE INDEX "index_followers_on_leader_id" ON "followers" ("leader_id")/Users/Steven/.rvm/gems/ruby-2.1.3/gems/sqlite3-1.3.10/lib/sqlite3/database.rb:91:in `initialize'
As the error says, you don't have a column named leader_id. You should change your migration to:
def change
create_table :followers do |t|
t.integer :follower_id
t.integer :leader_id
t.timestamps
end
add_index :followers, :follower_id
add_index :followers, :leader_id
add_index :followers, [:follower_id, :leader_id], unique: true
end
or rather change leader_id by followed_id.
You should also check the references modifier in activerecord migrations (source).
Your table does not have a column leader_id. You can see that because you are creating the table in the migration, and only specifying 3 columns, not of which is leader_id. But you are trying to add an index using that column, which is what generates the error. If you don't want that column anymore, you need to change the index. If you do want it, then do as jihonora suggests.
Related
rake db:migrate works locally in sqlite3 but does not work in postgresql in heroku.
ERROR
PG::UndefinedTable: ERROR: relation "musicians" does not exist
: ALTER TABLE "orders" ADD CONSTRAINT "fk_rails_ad134589be"
FOREIGN KEY ("musician_id")
REFERENCES "musicians" ("id")
(0.9ms) ROLLBACK
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "musicians" does not exist
: ALTER TABLE "orders" ADD CONSTRAINT "fk_rails_ad134589be"
FOREIGN KEY ("musician_id")
Here is a link to the entire log: https://gist.github.com/helloravi/2cb69e0927e63e186b09
The following is the migration which does not get executed. The error is displayed below the migration code
class CreateAlbums < ActiveRecord::Migration
def change
create_table :albums do |t|
t.string :album_name
t.references :musician, index: true, foreign_key: true
t.timestamps null: false
end
add_foreign_key :albums, :users, column: :musician_id
end
end
I have a users table with a musician column which is boolean(some users are musicians)
I even tried using add_foreign_key and still I am not able to figure out what the problem is.
I tried rake db:schema:load and it worked. I want to be able to make rake db:migrate work because I need to be able to migrate in production.
SQLite does not check foreign keys, it simply ignores them. But PostgreSQL is very strict and raises an error when the foreign key constraint is not valid.
Rails foreign_key does not support what you want it to do. When you write t.references :musician then there must be a musicians table. But you want the foreign key to point to a users table.
I see two options:
Use t.references :users and rename that association in your albums.rb like this:
belongs_to :musician, class_name: 'User', foreign_key: 'user_id'
Or: you just use t.integer :musician_id instead of references and define the foreign key constraint manually with an execute 'ALTER TABLE ...'
What #spickermann said is correct.
Changing your migration to the following should work:
class CreateAlbums < ActiveRecord::Migration
def change
create_table :albums do |t|
t.string :album_name
t.integer :musician_id
t.timestamps null: false
end
add_foreign_key :albums, :users, column: :musician_id
add_index :albums, :musician_id
end
end
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.
I was only able to discouver this problem by slowly walking through running my migrations. For the last two days I've been trying to do somthing simple. Remove one column verdict:text from my simulations table and add another column: opinions:hash.
Doing this caused a variety of errors, such as no method 'my_sym' and saying the simulation table didn't exist.
I initially thought I had resolved this by doing:
rake db:drop
rake db:schema:dump
rake db:migrate VERSION="<Migration1>"
rake db:migrate VERSION="<Migration2>"
rake db:setup ENV="test"
Migration 1:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => "", limit: 96
t.string :encrypted_password, :null => false, :default => "", limit: 60
t.timestamps
t.index :email, unique: true
end
end
end
Migration 2:
class CreateSimulations < ActiveRecord::Migration
def change
# Needs the hash column worked out before this is run
create_table :simulations do |t|
t.integer :x_size
t.integer :y_size
t.string :verdict
t.string :arrangement
end
add_reference :simulations, :user, index: true
end
end
This got me back to square one (all my tests worked everything seemed to be in my initial state I had before started having problems), so I re-wrote the two offending migrations thinking they might be the problem, ran the two migrations in this order (I removed the column then added the other one, the opposite order of what I tried previous, thinking maybe the order had some effect).
Migration 3:
class RemoveVerdictFromSimulation < ActiveRecord::Migration
def change
remove_column :simulations, :verdict, :string
end
end
Migrations 4:
class AddOpinionToSimulations < ActiveRecord::Migration
def change
add_column :simulations, :opinion, :hash
end
end
Edit: With further investigation it is this 4th migration that is causing the problem of dropping the simulations table without error.
Both these migrations worked without error. However I know doing anything else will cause an error (example running rspec), because it looks like the problem is that one of these migration causes an error with the schema.rb file.
After running these last migrations 3&4 my schema.rb which previously had both users and simulations tables now looks like this:
ActiveRecord::Schema.define(version: 20150807193122) do
# Could not dump table "simulations" because of following NoMethodError
# undefined method `[]' for nil:NilClass
create_table "users", force: :cascade do |t|
t.string "email", limit: 96, default: "", null: false
t.string "encrypted_password", limit: 60, default: "", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
end
The particular line of interest here being:
# Could not dump table "simulations" because of following NoMethodError
# undefined method `[]' for nil:NilClass
Can anyone shed some light on whats happening here or how I can fix it? I've been stuck on this for hours.
One thing maybe worth noting, when I re-run the rake db:schema:dump I need too comment out my factories for some reason, as they seem to cause errors with simulation table existing. Not sure why they're being called just thought this info might help, here they both are:
FactoryGirl.define do
factory :simulation do |f|
f.id (Simulation.last.nil? ? 1 : Simulation.last.id + 1)
f.x_size 3
f.y_size 3
f.user_id 1
end
end
--
FactoryGirl.define do
factory :user do
email "user_#{User.last.nil? ? 1 : User.last.id + 1}#home.com"
password "password"
end
end
I think the problem is right here:
class AddOpinionToSimulations < ActiveRecord::Migration
def change
add_column :simulations, :opinion, :hash
end
end
There's no such thing as hash column type. SQLite will, unfortunately, let you create columns with any type you want (with unrecognized things being treated as strings) but ActiveRecord won't know what to do with them. The result is that your migration works but the schema dump fails because ActiveRecord can't say:
t.hash :opinion
in the schema.rb file.
If you really think you want to store a Hash in a column, you'd create a text column:
add_column :simulations, :opinion, :text
and then use serialize in your model:
serialize :opinion, Hash
Of course that leaves you with an opaque blob of YAML in your database that you won't be able to (sanely) query so it should only be used if you are okay with that.
A better solution would be to normalize your opinion Hashes so that you could store their information in separate tables/models.
Locally, my migrations are fine (although I'm using SQLite. Will switch to postgresql on development asap).
After resetting the database on Heroku with
heroku pg:reset DATABASE
I ran
heroku run rake db:migrate
But I am getting the following error after a migration:
== AddForeignKeysToCollaborations: migrating =================================
-- change_table(:collaborations)
rake aborted!
An error has occurred, this and all later migrations canceled:
PG::Error: ERROR: relation "member1_id" does not exist
: ALTER TABLE "collaborations" ADD CONSTRAINT "collaborations_member1_id_id_fk" FOREIGN KEY ("member1_id_id") REFERENCES "member1_id"(id) ON DELETE CASCADE
Here is that migration:
class AddForeignKeysToCollaborations < ActiveRecord::Migration
def change
change_table :collaborations do |t|
t.foreign_key :member1_id, dependent: :delete
t.foreign_key :member2_id, dependent: :delete
end
end
end
Previous migrations for Collaborations are
class CreateCollaborations < ActiveRecord::Migration
def change
create_table :collaborations do |t|
t.integer :user_id
t.integer :collaborator_id
t.timestamps
end
add_index :collaborations, :collaborator_id
add_index :collaborations, [:user_id, :collaborator_id], unique: true
end
end
and
class UpdateCollaborations < ActiveRecord::Migration
def change
change_table :collaborations do |t|
t.rename :user_id, :member1_id
t.rename :collaborator_id, :member2_id
t.string :status
end
add_index :collaborations,:member1_id
add_index :collaborations,:member2_id
end
end
Which are run in that order. Why is this error coming up on Heroku? Specifically, it looks like PG is adding an unnecessary "_id" to "member1_id"
You're calling foreigner's methods with the wrong arguments. The first argument is the referenced table name not the referencing column name. And since your column names don't nicely match the table names you'll need :column options as well. Something like this:
t.foreign_key :users, :column => :member1_id, :dependent => :delete
That assumes that :users is the table name that your :member1_id and :member2_id columns should be pointing at.
The error message:
relation "member1_id" does not exist
tells you that PostgreSQL is looking for a table called member1_id but can't find it.
I'm in the process of adding Devise to an existing Rails app, with a Users table already defined. The devise generator pushed out the following migration:
class AddDeviseToUsers < ActiveRecord::Migration
def self.up
change_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0
blah blah blah....
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
end
The downward migration isn't generated, and I'm having a heck of a time removing those indexes. I'm seeing different suggested notation in the documentation, and different suggestions online, but none of them seem to be working for me. For example...
def self.down
change_table(:users) do |t|
t.remove :email
t.remove :encrypted_password
t.remove :reset_password_token
blah blah blah...
end
remove_index :users, :email
remove_index :users, :reset_password_token
end
results in...
An error has occurred, this and all later migrations canceled:
Index name 'index_users_on_email' on table 'users' does not exist
which is odd, because if I check the database, sure enough, 'index_users_on_email' is right there...
I've tried other variations, including
remove_index :users, :column => :email
remove_index :users, 'email'
or:
change_table(:users) do |t|
t.remove_index :email
end
...but no dice. I'm running Rails 3.1.0, Ruby 1.9.2, rake 0.9.2.2, with Postgres.
The command that's letting me down is:
bundle exec rake db:rollback STEP=1
after successfully apply the migration up. Any advice?
For the record, the way to remove an index by name is
remove_index(:table_name, :name => 'index_name')
so in your case
remove_index(:users, :name => 'index_users_on_email')
You can also remove the index specifying the columns, which from my point of view is less error prone than writing the name
remove_index :actions, :column => [:user_id, :action_name]
Depending on the database type, you don't need to worry about removing the indexes in the self.down method since the index will automatically be removed from the database when you drop the column.
You can also use this syntax in your self.down method:
def self.down
remove_column :users, :email
remove_column :users, :encrypted_password
remove_column :users, :reset_password_token
end
I'd like to expand on #iWasRobbed's answer. If you have index on just single column then worrying about remove_index doesn't make sense since (just an assumtion!) the DB should be smart enough to cleanup the resources used by that index. But in case you have multiple columns index removing the column will reduce index to still existing columns, which is totally sensible thing to do, but kind of shows where you might want to use remove_index explicitely.
Just for illustration - migration below has that flaw that after being applied up and down it will leave the unique index on email (meaning the down part is not doing its job properly)
class AddIndexes < ActiveRecord::Migration
def up
add_column :users, :action_name, :string
add_index :users, [:email, :action_name], unique: true
end
def down
remove_column :users, :action_name
end
end
Changing the down block to
def down
remove_index :users, [:email, :action_name]
remove_column :users, :action_name
end
will fix that flaw and allow the migration to correctly return DB to the previous state with rake db:rollback
To alter a table and/or its indeces use #change_table inside #change action of a migration. Then you be able to create reversable index removal as follows:
def change
change_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
When you have to drop a table with its index of course with reversable action you can use #drop_table method for SchemaStatements with the #index method of Table class for ConnectionAdapter:
def change
drop_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
In case you have need exactly the #up/down pair in a migration. Use just a #change_table method along with #remove_index method of Table class for ConnectionAdapter:
def up
change_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
def down
change_table :users do |t|
t.remove_index :email, :unique => true
t.remove_index :reset_password_token, :unique => true
end
end
All of the methods are available in Rails version of 2.1.0 or of earlier ones.
Here is my full run of this(in Rails 5):
I have team_id as an index in table vendors. I no longer need this relation. To get rid of it. Did the following:
1) create the migration.
$ rails generate migration RemoveTeam_idFromVendor team_id:integer
2) Running the migration, give me this error. And that is because vendor table has rows whose foreign key references the primary key value of the team table
== 20170727202815 RemoveTeamIdFromVendor: migrating ===========================
-- remove_column(:vendors, :team_id, :integer)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "vendors"
3) To solve this and get the migration running, I did the following(Note: i am in dev):
$ rake db:drop
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
$ rake db:create
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
$ rake db:migrate
~
~
~
== 20170727202815 RemoveTeamIdFromVendor: migrating ===========================
-- remove_column(:vendors, :team_id, :integer)
-> 0.0185s
== 20170727202815 RemoveTeamIdFromVendor: migrated (0.0185s) ==================