LoginSignup
37
22

More than 1 year has passed since last update.

Railsで主キーをid以外に設定し、ほかのテーブルとアソシエーションを結ぶ

Last updated at Posted at 2020-06-16

先日、どうしてもテーブルの主キーをID以外に変えなければならない状況になり、依存関係もあるテーブルの主キーを変更したのですが、個人的にはかなり躓いてしまったので、手順をメモします。

やったこと

実施したことは以下の通り。

  • マイグレーションファイルを変更(参照先テーブル、参照元テーブル)
  • モデルの変更(参照先テーブル、参照元テーブル)

なお、環境は以下の通り

  • Rails 5.2.4.2
  • Postgresql 12.2

マイグレーションファイルの変更

参照先テーブルの設定

officesテーブルに従属するstaffsテーブルがあったとします。
officesテーブルの主キーはoffice_codeとします。

この時officeテーブルを作成するマイグレーションの設定は下記のとおりです。

migration
class CreateOffices < ActiveRecord::Migration[5.2]
  def change
    create_table :offices, id: false do |t|  # id: falseを追加
      t.string  :name, null: false
      t.integer :office_code, null: false, primary_key: true  # primary_key: trueを追加
  
      t.timestamps
    end
  end
end

id: falseで自動で主キーをIDにする設定を解除します。
次に、primary_key: true で明確にoffice_codeを主キーに設定します。
参照される側のテーブルの設定はこれで終わりです。

参照元テーブルの設定

次に、staffsテーブルからofficeテーブルをoffice_codeという外部キーで参照したいと思います。
この時のマイグレーションファイルの設定は下記のとおりです。

class CreateStaffs < ActiveRecord::Migration[5.2]
  def change
    create_table :staffs do |t|
      t.string     :name, null: false
      t.references :office, null: false  #foreign_key: true は設定しない

      t.timestamps
    end
    add_foreign_key :staffs, :offices, column: :office_code , primary_key: :office_code
    # ここで外部キーを設定
  end
end

t.references :officeでofficesテーブルを参照することを宣言しますが、ここでforeign_key: trueを設定しないのがポイントです(ここでだいぶはまった…)。
foreign_key: trueを設定するとoffice_idを参照し続けてしまいます。

そして、マイグレーションファイルの下方に

add_foreign_key :参照元テーブル, :参照先テーブル, column: :参照するカラム , primary_key: :参照するテーブルの主キー

を記述します。

モデルの変更(参照先テーブル、参照元テーブル)

参照先テーブル

参照先テーブルであるoffice.rbのモデルファイルの設定は下記の通り。

office.rb
class Office < ApplicationRecord
  self.primary_key = :office_code  # ここに追記

  has_many :staffs

  validates :name, presence: true
  validates :office_code,   presence: true
end

まず、self.primary_key = 'カラム名'で主キーを設定します。
これによってfindメソッドでoffice_codeによる検索が可能になります。

参照元テーブル

最後に、officesテーブルを参照しているstaffsテーブルのモデルの記載について

staffs.rb
class Staff < ApplicationRecord
  belongs_to :office, primary_key: :office_code # ここに追記

  validates :office_id, presence: true
  validates :name, presence: true, length: { maximum: 50 }
end

primary_key: :office_codeの部分で、staffsテーブルからデータを参照するときの主キーを:office_codeに変更します。

上記で、無事、依存関係のあるテーブルにおいて、主キーをIDから変更し、アソシエーションを定義することができました。
まだ理解があいまいな点もあるので、間違いを発見したら修正していこうと思います。

参考情報

Railsで規約に沿わない古いデータを扱う
[Rails] 主キーがid以外のテーブルを外部キーに設定する方法
Active Record の関連付け
Rails で id 以外を主キー(primary_key)に設定する

37
22
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
22