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:
locations.csv:
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
On
CreateNames
migration you may useprimary_key: :fsa_id
option.CreateLocations
migration remain as you have posted.Also you need setup associations in models like:
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.