7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

1つのモデルに別の1つのモデルを複数個持たせる方法[Rails5]

Last updated at Posted at 2019-09-26

1つのモデルに別の1つのモデルを複数個持たせる方法

rails5にて[Rails] 同じmodelを参照する外部キーを一つのmodelでもつ方法
同様のことを実施したらdbへの登録時に

ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: main.receivers:

エラーが出てハマったので備忘録

環境

ruby 2.3.5
rails 5.2.3

やりたいこと

  1. MemberモデルとMoneyRecordモデルがある
  2. MoneyRecordモデルに送り主(Sender)と受取人(Receiver)を持たせる
  3. SenderとReceiverはMemberモデルと紐づける

dbは以下の通り

members

カラム名
id integer/primary
member_name string
created_at timestamp
updated_at timestamp

money_records

カラム名
id integer/primary
sender_id FK
receiver_id FK
created_at timestamp
updated_at timestamp

解決法

マイグレーションファイル

マイグレーションファイルに to_table オプションをつけることで
参照先テーブル名を明示的に指定してあげればできます。
参照:マイグレーションにおいて参照先テーブル名を自動で推定できないカラムを外部キーとして指定する方法

money_recordsのsenderとreceiverの foreign_key: true を以下に書き換え

create_money_records.rb
class CreateMoneyRecords < ActiveRecord::Migration[5.2]
  def change
    create_table :money_records do |t|
      t.references :sender, foreign_key: { to_table: :members }
      t.references :receiver, foreign_key: { to_table: :members }

      t.timestamps
    end
  end
end

※membersのマイグレーションはデフォルトでOK

create_member.rb
class CrceateMembers < ActiveRecord::Migration[5.2]
  def change
    create_table :members do |t|
      t.string :member_name

      t.timestamps
    end
  end
end

モデル

Memberモデルからはクラス名と外部キーを、MoneyRecordモデルからはクラス名を指定してあげる。

member.rb
class Member < ApplicationRecord
  has_many :sender_records,   class_name: 'MoneyRecord', foreign_key: 'sender_id'
  has_many :receiver_records, class_name: 'MoneyRecord', foreign_key: 'receiver_id'
end
money_record.rb
class MoneyRecord < ApplicationRecord
  belongs_to :sender,   class_name: 'Member'
  belongs_to :receiver, class_name: 'Member'
end

結果

登録

pry(main)> member_1 = Member.new(member_name: "hoge")
=> #<Member:0x00007f0db4c23e68 id: nil, member_name: "hoge", created_at: nil, updated_at: nil>

pry(main)> member_1.save
   (0.1ms)  begin transaction
  Member Create (3.1ms)  INSERT INTO "members" ("member_name", "created_at", "updated_at") VALUES (?, ?, ?)  [["member_name", "hoge"], ["created_at", "2019-09-26 03:08:49.593452"], ["updated_at", "2019-09-26 03:08:49.593452"]]
   (3.6ms)  commit transaction
=> true

pry(main)> member_2 = Member.new(member_name: "fuga")
=> #<Member:0x00007f0db4b0d420 id: nil, member_name: "fuga", created_at: nil, updated_at: nil>

pry(main)> member_2.save
   (0.1ms)  begin transaction
  Member Create (5.2ms)  INSERT INTO "members" ("member_name", "created_at", "updated_at") VALUES (?, ?, ?)  [["member_name", "fuga"], ["created_at", "2019-09-26 03:09:47.400686"], ["updated_at", "2019-09-26 03:09:47.400686"]]
   (4.0ms)  commit transaction
=> true

[6] pry(main)> mr = MoneyRecord.new(sender: member_1, receiver: member_2)
=> #<MoneyRecord:0x00007f0db497ed48 id: nil, sender_id: 1, receiver_id: 2, created_at: nil, updated_at: nil>

[7] pry(main)> mr.save
   (0.1ms)  begin transaction
  MoneyRecord Create (2.2ms)  INSERT INTO "money_records" ("sender_id", "receiver_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["sender_id", 1], ["receiver_id", 2], ["created_at", "2019-09-26 03:10:10.874060"], ["updated_at", "2019-09-26 03:10:10.874060"]]
   (4.0ms)  commit transaction
=> true

# 無事登録できた!

参照

# MoneyRecord -> Member の参照
pry(main)> mr.sender
=> #<Member:0x00007f0db4c23e68 id: 1, member_name: "hoge", created_at: Thu, 26 Sep 2019 03:08:49 UTC +00:00, updated_at: Thu, 26 Sep 2019 03:08:49 UTC +00:00>

pry(main)> mr.receiver
=> #<Member:0x00007f0db4b0d420 id: 2, member_name: "fuga", created_at: Thu, 26 Sep 2019 03:09:47 UTC +00:00, updated_at: Thu, 26 Sep 2019 03:09:47 UTC +00:00>

# 参照できてた!

# Member -> MoneyRecord の参照
pry(main)> member_1.sender_records[0]
=> #<MoneyRecord:0x00007f0db4625fc0 id: 1, sender_id: 1, receiver_id: 2, created_at: Thu, 26 Sep 2019 03:10:10 UTC +00:00, updated_at: Thu, 26 Sep 2019 03:10:10 UTC +00:00>

pry(main)> member_2.receiver_records[0]
=> #<MoneyRecord:0x00007f0db459c1f8 id: 1, sender_id: 1, receiver_id: 2, created_at: Thu, 26 Sep 2019 03:10:10 UTC +00:00, updated_at: Thu, 26 Sep 2019 03:10:10 UTC +00:00>

# 参照できてた!
7
3
0

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
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?