Search code examples
ruby-on-railspostgresqlherokurails-activerecordrails-migrations

Heroku migration fails UndefinedTable Error


I am using sqlite in development and test and deploying to Heroku which uses Postgres in production. I created a new model for 'Reviews' by running the following commands in the Terminal:

rails g model Review comment:text star:integer room:references reservation:references guest:references host:references type
rails g model GuestReview --parent=Review --migration=false
rails g model HostReview --parent=Review --migration=false
rails db:migrate

This is the output for the above commands:

$ rails g model Review comment:text star:integer room:references reservation:references guest:references host:references type
Running via Spring preloader in process 6862
  invoke  active_record
  create    db/migrate/20180613031058_create_reviews.rb
  create    app/models/review.rb
  invoke    test_unit
  create      test/models/review_test.rb
  create      test/fixtures/reviews.yml

$ rails g model GuestReview --parent=Review --migration=false
Running via Spring preloader in process 6872
  invoke  active_record
  create    app/models/guest_review.rb
  invoke    test_unit
  create      test/models/guest_review_test.rb
  create      test/fixtures/guest_reviews.yml

$ rails g model HostReview --parent=Review --migration=false
Running via Spring preloader in process 6880
  invoke  active_record
  create    app/models/host_review.rb
  invoke    test_unit
  create      test/models/host_review_test.rb
  create      test/fixtures/host_reviews.yml

$ rails db:migrate
== 20180613031058 CreateReviews: migrating 
====================================
-- create_table(:reviews)
-> 0.0806s
== 20180613031058 CreateReviews: migrated (0.0828s) 
===========================

The website functions normally in development on localhost and I am able to save reviews correctly when I examine the data in sqlite. When I deploy to Heroku and run

heroku run rake db:migrate 

I get the following error:

rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  relation "guests" does not exist
: CREATE TABLE "reviews" ("id" serial primary key, "comment" text, 
"star" integer DEFAULT 1, "room_id" integer, "reservation_id" integer, 
"guest_id" integer, "host_id" integer, "type" character varying, 
"created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL, 
CONSTRAINT "fk_rails_b98b7304fe"
FOREIGN KEY ("room_id")
  REFERENCES "rooms" ("id")
, CONSTRAINT "fk_rails_628a43e51f"
FOREIGN KEY ("reservation_id")
  REFERENCES "reservations" ("id")
, CONSTRAINT "fk_rails_eaa1ce2871"
FOREIGN KEY ("guest_id")
  REFERENCES "guests" ("id")
, CONSTRAINT "fk_rails_ac5cb4d097"
FOREIGN KEY ("host_id")
  REFERENCES "hosts" ("id")
)

Here is the migration file for Reviews:

class CreateReviews < ActiveRecord::Migration[5.0]
  def change
    create_table :reviews do |t|
      t.text :comment
      t.integer :star, default: 1
      t.references :room, foreign_key: true
      t.references :reservation, foreign_key: true
      t.references :guest, foreign_key: true
      t.references :host, foreign_key: true
      t.string :type

      t.timestamps
    end
  end
end

Here is the Review model:

class Review < ApplicationRecord
end

Here is the guest_review model:

class GuestReview < Review
  belongs_to :guest, class_name: "User"
end

Here is the host_review model:

class HostReview < Review
  belongs_to :host, class_name: "User"
end

It seems on Heroku Postgres it is looking for a guests table which does not exist. Is there a way to resolve this error so it functions correctly in my development environment and in Heroku?


Solution

  • In a migration, t.references :guest, foreign_key: true does two things:

    1. It creates an integer (or bigint depending on your Rails version) column named guest_id.
    2. It adds a foreign key constraint inside the database from the guest_id column to the id column in the guests table.

    But the table you're trying to reference is users (i.e. the User model), not guests. Since the names don't match up, you have to adjust the t.references call to tell ActiveRecord which table to reference:

    t.references :guest, foreign_key: { to_table: :users }
    

    Similarly for any other t.references calls where the table name cannot be inferred.


    Once you fix your immediate problem, you really should install PostgreSQL in your development environment so that you can develop, test, and deploy on the same stack. ActiveRecord doesn't provide database portability beyond the simplest and most trivial of things so using difference databases for development and deployment is a recipe for disaster.