Error adding foreign_key - ruby-on-rails

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.

Related

Can't migrate to heroku (Ruby on Rails tutorial [Michael Hartl] chaper 10)

I am working through chapter 10 of the Hartl book. In the conclusion of this chapter, we reset the heroku database and then migrate. However when I run:
heroku run rails db:migrate
I get an error:
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedColumn: ERROR: column "password_digest_string" of relation "users" does not exist
: ALTER TABLE "users" DROP "password_digest_string"
Earlier in the tutorial, I removed a column called password_digest_string because it was named incorrectly and I didn't need it yet. It seems like rails is trying to delete the column again even though it isn't there anymore. I deleted the migration file that removed this column but it still is trying to drop it. What's also odd is that I've migrated the database several times since dropping that column and never had this issue until I reset it. Any suggestions?
EDIT:
here is my schema file:
ActiveRecord::Schema.define(version: 20170121224748) do
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.boolean "admin", default: false
t.index ["email"], name: "index_users_on_email", unique: true
end
end
EDIT:
And my migrations in time-stamp order.
..._create_users.rb
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
..._add_index_to_users_email.rb
class AddIndexToUsersEmail < ActiveRecord::Migration[5.0]
def change
add_index :users, :email, unique: true
end
end
..._add_password_digest_to_users.rb
class AddPasswordDigestToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :password_digest, :string
end
end
..._remove_columns.rb
class RemoveColumns < ActiveRecord::Migration[5.0]
def self.up
remove_column :users, :password_digest_string
end
end
..._add_remember_digest_to_users.rb
class AddRememberDigestToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :remember_digest, :string
end
end
..._add_admin_to_users.rb
class AddAdminToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :admin, :boolean, default: false
end
end
It looks to me that the AddPasswordDigestToUsers migration initially looked like this (probably you misspelled):
class AddPasswordDigestToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :password_digest_string
end
end
Then you realized the column should be just password_digest. So you manually edited the migration file to what it looks now, rolled back, created the next migration which is RemoveColumns and then ran migration.
Now when you the migrations from the beginning, there will be no error if you are using sqlite3 (which is what you use for dev environment) due to the way column removal is handled in sqlite. But there will be an error if you use Postgres.
What you should have done
Instead of what you did, you should have just created a migration to change the column name, like this:
class RenamePasswordDigestStringColumn < ActiveRecord::Migration[5.0]
def self.up
rename_column :users, :password_digest_string, :password_string
end
end
What you can do now
To get past the problem without doing many changes now, you can just delete the RemoveColumns migration (and commit, push... etc that). That would be OK and I don't think it will harm your production or development environments.
$> heroku pg:reset DATABASE will make the db:migrate on heroku clean again

PG::UndefinedTable: ERROR: relation "musicians" does not exist

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

Rails 4: schema.db shows "Could not dump table "events" because of following NoMethodError# undefined method `[]' for nil:NilClass"

I've been working on a Rails 4.0 application with sqlite (default for Rails development environment) for events (hackathons) which has a parent model, Event, for which there can be many Press_Blurbs.
First I ran some scaffolding generators which created some migrations that I ran seemingly without issue:
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.string :city
t.string :theme
t.datetime :hackathon_start
t.datetime :hackathon_end
t.datetime :show_start
t.datetime :show_end
t.text :about
t.string :hack_rsvp_url
t.string :show_rsvp_url
t.timestamps
end
end
end
class CreatePressBlurbs < ActiveRecord::Migration
def change
create_table :press_blurbs do |t|
t.string :headline
t.string :source_name
t.string :source_url
t.string :logo_uri
t.timestamps
end
end
end
Then I added some relationships to the models:
class Event < ActiveRecord::Base
has_many :press_blurbs
end
class PressBlurb < ActiveRecord::Base
belongs_to :event
end
...and added/ran a migration to add a table reference:
class AddEventRefToPressBlurbs < ActiveRecord::Migration
def change
add_column :press_blurbs, :event, :reference
end
end
Nevertheless, when I look at schema.db this is what I see instead of tables definitions:
# Could not dump table "events" because of following NoMethodError
# undefined method `[]' for nil:NilClass
# Could not dump table "press_blurbs" because of following NoMethodError
# undefined method `[]' for nil:NilClass
Other unrelated tables show up in schema.rb perfectly fine, but these do not. Any idea what's going on?
I think your last migration is wrong. I would change it to this:
class AddEventRefToPressBlurbs < ActiveRecord::Migration
def change
add_reference :press_blurb, :event
end
end
Unfortunately, your database is likely in a wonky state because it has an invalid column type (i.e. there is no 'reference' column type, but sqlite made it anyway). Hopefully, it's just a development database so you can just delete it and start fresh.
Just in case this helps someone. I was doing this on a sqlite dev db, and as mentioned above, it was likely in a wonky state from all my experimental migrations. By deleting the sqlite file, recreating and running all the migrations, it is now fine.

When running migrations on Heroku, I get PG::Error: ERROR: relation "member1_id" does not exist

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.

Duplicate column name error when running migration

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

Resources