在 Rails 的 Ruby 中的现有列上创建外键

Creating a foreign key on an exisiting column in Ruby on Rails

我正在尝试在 Rails 上的 Ruby 中创建两个 table,它们都将通过播种 CSV 文件来填充。这两个文件都已经包含一个 ID 列 fsa_id,我想将其用作 table 的 primary/foreign 键。

到目前为止,我有以下 table 个迁移:

姓名:

  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

地点:

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

我想要做的是使 fsa_id 成为名称 table 的主键和位置 table.

的外键

据我所知,我可以通过将以下内容添加到位置迁移文件来做到这一点:

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

但是,当我添加它并尝试 运行 rails db:migrate 时,我收到以下错误:

== 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)

我试过环顾四周,但大多数答案似乎假设要么使用 table 的 id,要么 table 会自行增长。

作为数据库种子的 CSV 文件的完整参考布局如下:

names.csv:

locations.csv:

如果有人能帮助解决这个问题,我将不胜感激。

编辑:

我在生产中使用 Postgress:

我的Gemfile如下:

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]

CreateNames 迁移中,您可以使用 primary_key: :fsa_id 选项。

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 迁移与您发布的一样。

您还需要在以下模型中设置关联:

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

如果您想修改现有的外键或向其添加外键 table,您应该创建一个新的迁移以避免在生产中破坏代码。