82747
# 前提

現在以下のようなテーブルで多対多の関係を持たせたいと考えています。  
フレームワークは Ruby on Rails、DBは PostgreSQL です。

[![多対多の関係図](https://i.stack.imgur.com/6h2j0.png)](https://i.stack.imgur.com/6h2j0.png)

  * 曲は複数の作曲者、作詞者、編曲者をもつ
  * アーティストは複数の曲を持つ

ような関係です。

* * *

そこで、有識者の方から、中間テーブルをそれぞれに用意して以下のようにすればいいのではと助言していただきました。

[![中間テーブル](https://i.stack.imgur.com/hKeUW.png)](https://i.stack.imgur.com/hKeUW.png)

# 状況

助言の意図は理解できたつもりだったのですが、いまいちコーディングの仕方が分かりません。

最終的には、

  * アーティストの曲
  * 曲の作曲者
  * 曲の作詞者

という風にデータを参照できればと思っています。

# 質問

  * このようなリレーションでのモデルのカラムの書き方。
  * モデル(.rb)での`has_many`や`belongs_to`の書き方。
  * もしあれば、中間テーブルを使わないようなその他のアイディア。

以上３点についてお答えしていただければと思います。  
拙い文章でもうしわけありません。  
よろしくお願いします。
CC BY-SA 4.0
2021-09-28T15:55:20.383
82737
2021-09-29T06:10:52.007
2021-09-28T16:23:07.763
3060
47477
question
ruby-on-rails postgresql
Rails で複数の中間テーブルの作成方法がわからない
動かしたわけではないので参考程度にお願いします。  
ArtistとSongモデルはすでにあるという前提です。また、一般的なRailsモデルとしてidが主キーという理解で書いています

> このようなリレーションでのモデルのカラムの書き方。

モデルとマイグレーション生成

```

    $ rails g model ComposerSong
    $ rails g model LyricistSong
    $ rails g model ArrangerSong
    
```

各カラムの記述

```

    # db/migrates/xxxx_create_composer_songs.rb
    class CreateComposerSongs < ActiveRecord::Migration[6.1]
      def change
        create_table :composer_songs do |t|
            t.references :composer, foreign_key: { to_table: :artists }
            t.references :song, foreign_key: true
        end
      end
    end
    
    # db/migrates/xxxx_create_lyricist_songs.rb
    class CreateLyricistSongs < ActiveRecord::Migration[6.1]
      def change
        create_table :lyricist_songs do |t|
            t.references :lyricist, foreign_key: { to_table: :artists }
            t.references :song, foreign_key: true
        end
      end
    end
    
    # db/migrates/xxxx_create_arranger_songs.rb
    class CreateArrangerSongs < ActiveRecord::Migration[6.1]
      def change
        create_table :arranger_songs do |t|
            t.references :arranger, foreign_key: { to_table: :artists }
            t.references :song, foreign_key: true
        end
      end
    end
    
    
```

> モデル(.rb)でのhas_manyやbelongs_toの書き方。

ArtistとSongモデルはcomposer, lyricist,
arrangerという中間テーブルが3つありそれぞれにアクセスできる必要があります。このため、 `has_many :through`
の部分では中間テーブル名に_songsまたは_artistsをつけてアクセスする命名にしています。ここは好きに変更してください

SongやArtistの削除時の中間テーブルの振る舞いは書いていないので注意してください。

```

    # app/model/composer_song.rb
    class ComposerSong < ApplicationRecord
        belongs_to :composer, class_name: "Artist", foreign_key: "artist_id"
        belongs_to :song
    end
    
    # app/model/lyricist_song.rb
    class LyricistSong < ApplicationRecord
        belongs_to :lyricist, class_name: "Artist", foreign_key: "artist_id"
        belongs_to :song
    end
    
    # app/model/arranger_song.rb
    class ArrangerSong < ApplicationRecord
        belongs_to :arranger, class_name: "Artist", foreign_key: "artist_id"
        belongs_to :song
    end
    
    
    # app/model/artist.rb
    class Artist < ApplicationRecord
        has_many :composer_songs
        has_many :composer_song_songs, through: :composer_songs
    
        has_many :lyricist_songs
        has_many :lyricist_song_songs, through: :lyricist_songs
    
        has_many :arranger_songs
        has_many :arranger_song_songs, through: :arranger_songs
    end
    
    # app/model/song.rb
    class Song < ApplicationRecord
        has_many :composer_songs
        has_many :composer_song_artists, through: :composer_songs
    
        has_many :lyricist_songs
        has_many :lyricist_song_artists, through: :lyricist_songs
    
        has_many :arranger_songs
        has_many :arranger_song_artists, through: :arranger_songs
    end
    
```

> もしあれば、中間テーブルを使わないようなその他のアイディア。

私のほうでは特に良い実装は思いつきません
CC BY-SA 4.0
2021-09-29T06:10:52.007
82747
2021-09-29T06:10:52.007
298
82737
answer