質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

MVC

MVC(Model View Controller)は、オブジェクト指向プログラミングにおけるモデル・ビュー・コントローラーの総称であり、ソフトフェア開発で使われている構築パターンとしても呼ばれます。

Q&A

解決済

1回答

1511閲覧

Railsで多対多のコントローラの作り方が分からない

yosse95ai

総合スコア39

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

MVC

MVC(Model View Controller)は、オブジェクト指向プログラミングにおけるモデル・ビュー・コントローラーの総称であり、ソフトフェア開発で使われている構築パターンとしても呼ばれます。

1グッド

1クリップ

投稿2021/10/01 05:29

編集2021/10/01 05:33

前提

以下のような多対多のテーブルを有識者の方のアドバイスをもとに作成しました。
イメージ説明

しかし、私の知識が浅く、コントローラの作り方が分からなくなってしまいました。

フレームワークは Rails 6 系、DBは PostgreSQL 13 系です。

モデルの状態

ruby

1# app/models/song.rb 2class Song < ApplicationRecord 3 has_many :composer_songs, dependent: :destroy 4 has_many :composer_song_artists, through: :composer_songs 5 6 has_many :lyricist_songs, dependent: :destroy 7 has_many :lyricist_song_artists, through: :lyricist_songs 8 9 has_many :arranger_songs, dependent: :destroy 10 has_many :arranger_song_artists, through: :arranger_songs 11end 12 13# app/models/artist.rb 14class Artist < ApplicationRecord 15 has_many :composer_songs, dependent: :destroy 16 has_many :composer_song_songs, through: :composer_songs 17 18 has_many :lyricist_songs, dependent: :destroy 19 has_many :lyricist_song_songs, through: :lyricist_songs 20 21 has_many :arranger_songs, dependent: :destroy 22 has_many :arranger_songs_song, through: :arranger_songs 23end 24 25# app/models/lyricist_song.rb 26class LyricistSong < ApplicationRecord 27 belongs_to :lyricist, class_name: "Artist", foreign_key: "artist_id" 28 belongs_to :song 29end 30 31# app/models/composer_song.rb 32class ComposerSong < ApplicationRecord 33 belongs_to :composer, class_name: "Artist", foreign_key: "artist_id" 34 belongs_to :song 35end 36 37# app/models/arranger_song.rb 38class ArrangerSong < ApplicationRecord 39 belongs_to :arranger, class_name: "Artist", foreign_key: "artist_id" 40 belongs_to :song 41end

スキーマの状態

ruby

1# db/schema.b 2 3ActiveRecord::Schema.define(version: 2021_09_29_115047) do 4 5 # These are extensions that must be enabled in order to support this database 6 enable_extension "plpgsql" 7 8 create_table "arranger_songs", force: :cascade do |t| 9 t.bigint "arranger_id" 10 t.bigint "song_id" 11 t.index ["arranger_id"], name: "index_arranger_songs_on_arranger_id" 12 t.index ["song_id"], name: "index_arranger_songs_on_song_id" 13 end 14 15 create_table "artists", force: :cascade do |t| 16 t.string "name" 17 t.datetime "created_at", precision: 6, null: false 18 t.datetime "updated_at", precision: 6, null: false 19 end 20 21 create_table "composer_songs", force: :cascade do |t| 22 t.bigint "composer_id" 23 t.bigint "song_id" 24 t.index ["composer_id"], name: "index_composer_songs_on_composer_id" 25 t.index ["song_id"], name: "index_composer_songs_on_song_id" 26 end 27 28 create_table "lyricist_songs", force: :cascade do |t| 29 t.bigint "lyricist_id" 30 t.bigint "song_id" 31 t.index ["lyricist_id"], name: "index_lyricist_songs_on_lyricist_id" 32 t.index ["song_id"], name: "index_lyricist_songs_on_song_id" 33 end 34 35 create_table "songs", force: :cascade do |t| 36 t.string "name" 37 t.datetime "created_at", precision: 6, null: false 38 t.datetime "updated_at", precision: 6, null: false 39 end 40 41 add_foreign_key "arranger_songs", "artists", column: "arranger_id" 42 add_foreign_key "arranger_songs", "songs" 43 add_foreign_key "composer_songs", "artists", column: "composer_id" 44 add_foreign_key "composer_songs", "songs" 45 add_foreign_key "lyricist_songs", "artists", column: "lyricist_id" 46 add_foreign_key "lyricist_songs", "songs" 47end

試したこと

以下のような操作はちゃんとできました。

ruby

1Song.create(name: "test1") 2Song.create(name: "test2") 3Artist.create(name: "a1") 4Artist.create(name: "a2")

中間テーブルを多分ちゃんと覗けています。。。
今はまだ中間テーブルは空です。

ruby

1irb(main):012:0> Song.first.composer_songs 2 Song Load (0.6ms) SELECT "songs".* FROM "songs" ORDER BY "songs"."id" ASC LIMIT $1 [["LIMIT", 1]] 3 ComposerSong Load (0.7ms) SELECT "composer_songs".* FROM "composer_songs" WHERE "composer_songs"."song_id" = $1 [["song_id", 1]] 4=> []

実現したいこと

以下のような状態を実現できるコントローラーを記述したいです。

イメージ説明

しかし、どのようにしてSong.create(name: "test1")のような
createupdateの処理を記述したらいいのかわかりません。

私のような多対多のテーブルにおける、コントローラ(CRUD)の記述の仕方を教えていただきたいです。
よろしくお願いします。

shinoharat👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shinoharat

2021/10/01 09:30

画面的には「アーティストを登録する画面」と「曲名を入力し、作詞者・作曲者・編曲者を選んで楽曲を登録する画面」の2種類になるってイメージでいいんですかね? もしそうなら、Song モデルに「accepts_nested_attributes_for」を足した上で、 Song.create( name: "test1", composer_songs_attributes: { ... }, lyricist_songs_attributes: { ... }, arranger_songs_attributes: { ... }, ) みたいに書けば Song を登録するついでに関連付けも一緒に行えます。 実際のコントローラーでは permit とかも必要です。 これで方向性が合っていれば、もう少し詳しい回答を書きます。 -- それから、質問ではコントローラーの書き方に限定されていますが、 view の方は問題ないですか? 「fields_for」とか「_destroy」とか、ご存知なければそちらも解説しますが。
yosse95ai

2021/10/01 11:27 編集

返信が遅れました。 > 画面的には「アーティストを登録する画面」と「曲名を入力し、作詞者・作曲者・編曲者を選んで楽曲を登録する画面」の2種類になるってイメージでいいんですかね? その認識で間違いありません。 > それから、質問ではコントローラーの書き方に限定されていますが、 view の方は問題ないですか? APIモードで作成しているので、いまのところviewはなくても大丈夫かなと思っています。
guest

回答1

0

ベストアンサー

多対多の中間テーブルの作成はcontrollerを作って行うというよりは、、、、

例えば
test1 を a1 の composer_songs にいれるには
a1.composer_song_songs << test1
です。
a2 の composer_songs を test1, test2 に置き換えるなら
a2.composer_songs = [test1, test2]
です。

追記

関連定義に違和感があるのです
例えば has_many :composer_song_songs
これは CompoerSongSong というmodelをhas_manyしてるというもの。

ある Song を ComposerSong として Artistに関連付けるなら
中間tableは Artist と ComposerSong をつなぐものとして、 ArtistComposerSong で、
class Artist has_many :composer_songs, class_name: "Song", through: :artist_composer_songs
とするのがよいのでは。

投稿2021/10/01 09:30

編集2021/10/01 12:55
winterboum

総合スコア23416

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yosse95ai

2021/10/01 11:43

回答ありがとうございます。 以下のように行ってみましたが、なぜかうまくいきませんでした… ``` a1 = Artist.first test1 = Song.first a1.composer_song_songs << test1 ``` すると以下のようになりました… ``` /home/user/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-6.1.4.1/lib/active_record/reflection.rb:933:in `check_validity!': Could not find the source association(s) "composer_song_song" or :composer_song_songs in model ComposerSong. Try 'has_many :composer_song_songs, :through => :composer_songs, :source => <name>'. Is it one of composer or song? (ActiveRecord::HasManyThroughSourceAssociationNotFoundError) ``` このエラーについて調べてみたのですが、いまいち解決方法が見つかりませんでした。 そのため。返信が遅れて申し訳ありません。
yosse95ai

2021/10/14 08:45

追記ありがとうございます。 命名規則について無知なところがあるため、見直していきたいと思いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問