skip to Main Content

I am trying to create two tables in Ruby on Rails which are both to be populated by seeding CSV files. Both files already contain an ID column fsa_id that I would like to use as the primary/foreign keys for my tables.

So far I have the following table migrations:

names:

  class CreateNames < ActiveRecord::Migration[6.0]
  def change
    create_table :names do |t|
      t.integer :fsa_id
      t.string :name

      t.timestamps
    end
  end
end

Locations:

class CreateLocations < ActiveRecord::Migration[6.0]
  def change
    create_table :locations do |t|
      t.integer :fsa_id
      t.string :adress
      t.string :postcode
      t.integer :lattitude
      t.integer :longitude
      t.string :local_authority

      t.timestamps
    end
  end
end

What I am looking to do is make fsa_id the primary key on the names table and the foreign key on the locations table.

As I understand I can do this by adding the following to the locations migration file:

class CreateLocations < ActiveRecord::Migration[6.0]
  def change
    create_table :locations do |t|
      t.integer :fsa_id
      t.string :adress
      t.string :postcode
      t.integer :lattitude
      t.integer :longitude
      t.string :local_authority

      t.timestamps
    end
    # Adds a foreign key constraint to the fsa_id column
    # Links to the names table which uses the same named column.
    add_foreign_key :locations, 
                :names, 
                column: :fsa_id,
                primary_key: :fsa_id
  end
end

However, when I add this and try to run rails db:migrate I get the following error:

== 20201116221428 CreateLocations: migrating ==================================
-- create_table(:locations)
   -> 0.0017s
-- add_foreign_key(:locations, :names, {:column=>:fsa_id, :primary_key=>:fsa_id})
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::SQLException: foreign key mismatch - "locations" referencing "names"
/home/jonathon/Projects/waad/jpd_individual_2020/db/migrate/20201116221428_create_locations.rb:15:in `change'
/home/jonathon/Projects/waad/jpd_individual_2020/bin/rails:9:in `<top (required)>'
/home/jonathon/Projects/waad/jpd_individual_2020/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'

Caused by:
ActiveRecord::StatementInvalid: SQLite3::SQLException: foreign key mismatch - "locations" referencing "names"
/home/jonathon/Projects/waad/jpd_individual_2020/db/migrate/20201116221428_create_locations.rb:15:in `change'
/home/jonathon/Projects/waad/jpd_individual_2020/bin/rails:9:in `<top (required)>'
/home/jonathon/Projects/waad/jpd_individual_2020/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'

Caused by:
SQLite3::SQLException: foreign key mismatch - "locations" referencing "names"
/home/jonathon/Projects/waad/jpd_individual_2020/db/migrate/20201116221428_create_locations.rb:15:in `change'
/home/jonathon/Projects/waad/jpd_individual_2020/bin/rails:9:in `<top (required)>'
/home/jonathon/Projects/waad/jpd_individual_2020/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

I have tried looking around but most answers seem to assume either the id of the table is to be used or that the table will grow itself.

For full reference the CSV files to seed the database are laid out like this:

names.csv:

enter image description here

locations.csv:

enter image description here

If anyone could help with this issue I would be very grateful.

EDIT:

I am using Postgress in production:

my Gemfile is as follows:

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.5'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.3', '>= 6.0.3.4'
# Use sqlite3 as the database for Active Record
gem 'sqlite3', '~> 1.4', '>= 1.4.2', group: :production
# Use Puma as the app server
gem 'puma', '~> 4.1'
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'chartkick'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false

group :production do
  gem 'pg'
end
group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
 end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '~> 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

2

Answers


  1. On CreateNames migration you may use primary_key: :fsa_id option.

    class CreateNames < ActiveRecord::Migration[6.0]
      def change
        create_table :names, primary_key: :fsa_id do |t|
          t.string :name
    
          t.timestamps
        end
      end
    end
    
    

    CreateLocations migration remain as you have posted.

    Also you need setup associations in models like:

    class Name < ApplicationRecord
      has_one :location, primary_key: :fsa_id
    end
    
    class Location < ApplicationRecord
      belongs_to :name, foreign_key: :fsa_id, primary_key: :fsa_id
    end
    
    Login or Signup to reply.
  2. If you want to modify or add a foreign key to your existing table, you should create a new migration to avoid to break your code in production.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search