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

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

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

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

Q&A

解決済

1回答

1193閲覧

Ruby 3つの異なるテーブルデータを一度に保存したい

Malson

総合スコア10

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

0グッド

0クリップ

投稿2020/07/10 01:34

編集2020/07/10 09:52

前提・実現したいこと

rubyで、3つの異なるテーブルのデータを一度に保存したい。
モデルFolderのcreateアクション実行時に以下の3つの情報を格納したい

  • Folderテーブルに格納すべき情報、
  • 1:多数の関係にある親子関係のモデルCardの情報、
  • 1:多数の関係にあるモデルFolderUsersの情報

発生している問題・エラーメッセージ

エラーは表示されていないが、controllerで@folderが保存できない。

パラメータを確認したところidが全てnilになっている。何故idが生成されないかの理由が判然とせず、またcardsに関しては何一つデータを取得することもできていない

terminal

1[1] pry(#<FoldersController>)> @folder 2=> #<Folder:0x00007f9d009ce7e0 id: nil, name: "aaaa"> 3[2] pry(#<FoldersController>)> @folder.cards 4=> [#<Card:0x00007f9d00a2c2a0 id: nil, omote: nil, ura: nil, folder_id: nil>] 5[3] pry(#<FoldersController>)> @folder.folder_users 6=> [#<FolderUser:0x00007faa9d074f78 id: nil, folder_id: nil, user_id: 4>]

該当のソースコード

contoroller

1class FoldersController < ApplicationController 2 3 def index 4 @folders = Folder.all 5 end 6 7 def new 8 @folder = Folder.new 9 @folder.cards.build 10 end 11 12 def create 13 @folder = Folder.create(folder_params) 14 @folder.folder_users.new(user: current_user) 15 if @folder.save 16 redirect_to :root, notice: '新しいフォルダを作成しました' 17 else 18 render :new 19 end 20 end 21 ~~~~~~~~~~~~~~~~~~~~~~~略~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 private 23 def folder_params 24 params.require(:folder).permit( 25 :name, 26 cards_attributes: { 27 omote: [], 28 ura: [], 29 folder_id: [] 30 } 31 ) 32 end 33end 34

試したこと

補足情報(FW/ツールのバージョンなど)

table

1>> FolderUser 2=> FolderUser(id: integer, folder_id: integer, user_id: integer) 3>> Folder 4=> Folder(id: integer, name: string) 5>> Card 6=> Card(id: integer, omote: string, ura: string, folder_id: integer)

routes

1 ~~~略~~~ 2 resources :folders, only: [:index, :new, :create, :edit, :update] do 3 resources :cards, only: [:index, :new, :create, :edit] 4 end 5 ~~~略~~~

アドバイスに従い以下のファイルを追記いたします

ViewFile

1= form_with model: folder, local: true do |f| 2 = f.label :name, "フォルダ名" 3 = f.text_field :name 4 = f.fields_for :cards do |c| 5 = c.label :omote, "カード(問題)" 6 = c.text_area :omote 7 = c.label :ura, "カード(解答)" 8 = c.text_area :ura 9 = f.submit

FolderModel

1class Folder < ApplicationRecord 2 has_many :folder_users 3 has_many :users, through: :folder_users 4 has_many :cards, dependent: :destroy 5 accepts_nested_attributes_for :cards 6 validates :name, presence: true 7end

CardModel

1class Card < ApplicationRecord 2 belongs_to :folder, optional: true 3 validates :omote, presence: true 4 validates :ura, presence: true 5end

参考にした記事など
https://qiita.com/hmuronaka/items/580b977834d4b3010454
https://qiita.com/tseno/items/70d39f7c0e8e1c779b5e

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

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

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

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

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

Cojiro

2020/07/10 02:45

View, Modelのファイルと参考にした記事があれば記載した方がいいと思います。
Malson

2020/07/10 03:03

kojiro12345様、 アドバイスありがとうございます。補足事項に追記させていただきました。 質問の仕方や、問題がありそうな部位のピックアップなどまだハッキリとはできないため、申し訳ございません。 記載内容でわかりにくいところや、伝えるべきことがあれば御指南いただければと思います。 よろしくお願いいたします。
guest

回答1

0

ベストアンサー

foldersとcardsにはuser_idがないですが、folder_paramsでuser_idを与えており、Folder.create(folder_params)で、パラメーターをセットしているときにfolderにはuser_idがないというエラーかと思います。
.merge(user_id: current_user.id)を外せば、foldersとcardsの登録できると思います。

folder_usersも登録したいということであれば、
それはそもそも3つのテーブルを同時に登録するということになります。(もしこれがやりたかったことであれば、質問を正しくしましょう。そうでなければ、スルーしてください。)

コントローラーファットになっていくので、
いい方法ではないですが、
手っ取り早くfolder_usersも保存するのは、下記のようにすることでしょうか。

Ruby

1 def create 2 @folder = Folder.new(folder_params) #ここでエラー 3 @folder.folder_users.new(user: current_user) #追加 4 if @folder.save 5 redirect_to :root, notice: '新しいフォルダを作成しました' 6 else 7 render :new 8 end 9 end 10 11 private 12 def folder_params 13 params.require(:folder).permit( 14 :name, 15 cards_attributes: { 16 omote: [], 17 ura: [], 18 folder_id: [] 19 } 20 ) 21 # .mergeを削除 22 end

投稿2020/07/10 05:51

編集2020/07/10 09:45
Cojiro

総合スコア539

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

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

Malson

2020/07/10 06:06

ありがとうございます。 私がやりたかったのはご指摘の通り、3つのテーブルにデータを保存するということですので、タイトルから編集いたします。申し訳ございません。
Malson

2020/07/10 06:17

こうして考えると、 ストロングパラメータの属性にFolderUsersも追加して、user_idの置き場所を明確にしてやらないとダメってことなのでしょうか? 携帯からなので、これは後ほどチャレンジしてみたいとは思いますが、どう考えたら良いのでしょうか?
Cojiro

2020/07/10 06:21

> こうして考えると、 というのはどのように考えたのですか??
Malson

2020/07/10 06:27

実は指摘されるまで、3つのテーブルでということを全く意識してなかったので、 また、中間テーブルは、アソシエーションを組んでモデルでネストすれば、コントローラーで設定しなくても良いという認識がありましたが、そうでないのかもしれないと考えました。 超初心者なので検討外れのことも言うかもしれませんが、よろしくお願いいたします。
Malson

2020/07/10 09:30

kojiro12345様、 ありがとうございました。一歩前進できました。 そして、すいません、全く検討外れのコメントを返していました。 コードを良く読んで理解できました。 いただいたコードですが、newアクションで @folder.users << current_userという定義でも大丈夫かなと思うのですがどうでしょうか? ただ、エラーは起きなくなったのですが、やはり@folderが保存されずにrenderされてしまっているので何かがおかしいのですね。
Cojiro

2020/07/10 09:44

よかったです。 正直、なんて返せばいいかわからなかったです。 あとすいません。 createアクションの1行目は、 @folder = Folder.new(folder_params) になります。 修正リクエスト出します。 >いただいたコードですが、newアクションで @folder.users << current_userという定義でも大丈夫かなと思うのですがどうでしょうか? これは分かりません。やってみてください。
Malson

2020/07/10 10:12 編集

kojiro12345様、 createアクションの1行目も変更してみましたが、保存することができません。newではページに遷移するだけなので、この時点ではパラメータを代入すると、validationに引っかかるんですね。 そこで、presenceを削除すると機能することはするのですが、、、、 @folderは、nameを取得していて、@folder.folder_usersはuser_idを保持していますが、@folder.cardの情報は一切取得できていません。 これはもうviewファイルの書き方に問題があって、入力した情報を取得できていないと考えるべきなのでしょうか???
Cojiro

2020/07/10 10:25

> createアクションの1行目も変更してみましたが、保存することができません。 というのは、ログはどうなっていますか? あとは、@folder.errors.full_messagesはなんと表示されていますか? あと、 viewの = form_with model: folder, local: true do |f| のfolderってFolderのインスタンスですか? 意味がわからなかったらFolder.newに変更してみてください。
Malson

2020/07/10 11:21

createアクションで@folder = Folder.new(folder_params)に変更した上で、保存を実行するとrenderされます。 renderの直前で確認したところ、パラメータの中には情報が格納されていますが、unpermitted parameters: :omote, :uraとなっています。 また、[1] pry(#<FoldersController>)> @folder.errors.full_messages => ["Cards omoteを入力してください", "Cards uraを入力してください"] という表示になっています。Cardの情報だけは取得できていないです。 viewのform_withの記述方法ですが、 モデルのインスタンスを記載するということでしたので何も考えずにfolderとしてました。Folder.newですとcardの入力欄が表示されなくなってしまいました。このとき、Cardの以外は保存することはできます。
Cojiro

2020/07/10 13:35

なるほど。 よくみたらnewアクションで@folder作って、@folderに対してcardsをbuildしてますね。 (Folder.newでうまく行ったら案内しようと思っていました。) なので、modelを@folderにすれば、うまくいく気がします。 > 保存を実行するとrenderされます。 ごめんなさい。これはちょっと意味がわかりません。何がrenderされるんですか?
Malson

2020/07/10 13:45

kojiro12345様、 遅くまでありがとうございます。 saveされないとrender :newで戻る様にしています。 modelを@folderにしてはみたのですが、やはり同じでunpermitted parameterになってしまっています。
Cojiro

2020/07/10 13:58

よくみたら、ストロングパラメーター、おかしいですね。 cards_attributes: [ :ura, :omote ] にしてみてください。
Cojiro

2020/07/10 13:59

あと、folder_idも。
Malson

2020/07/10 15:44

kojiro12345様、 ありがとうございます。 精進が足りず、もはやどこがおかしいのかすらわかっていないのですが、子ストロングパラメータにfolder_idなどforeign_keyは記述は必要ないということですね。 [ ]を付けたのは、ストロングパラメーターの入力が成功したあとで多数入力できる様に変更したいと考えていて配列を意識したのですが、一つの時は一つの要素しか持たない配列にならないのでしょうか? それとも属性の名前だけ記述するので、余計ってことでしょうか?
Malson

2020/07/10 15:51

kojiro12345様、 長々とお付き合いいただき、本当にありがとうございました。 無事解決することができました。今回のことはしっかりと復習して身につけます。
Cojiro

2020/07/10 21:35

そうですね。 子モデルの同時登録は、少し時期尚早な気がしました。 今回のこともそうですが、Railsについてもっと基本を学んだ方がいいと思います。 > [ ]を付けたのは、ストロングパラメーターの入力が成功したあとで多数入力できる様に変更したいと考えていて配列を意識したのですが、 やりとりしていて思いましたが、Railsはあなたの思い通りではなく、Railsの仕様通りに動きます。 もちろん私のいう通りでもありません。 思い込みや誤った理解を応用しているように見えます。 思い込みや誤った理解は、そもそも推測であるはずなので、動作して確かめられていないものは動かして確かめる癖をつけた方がいいです。着実に事実に基づいて理解して実装するようにした方が結果として早く身につくと思います。 >[ ]を付けたのは、ストロングパラメーターの入力が成功したあとで多数入力できる様に変更したいと考えていて配列を意識したのですが、一つの時は一つの要素しか持たない配列にならないのでしょうか? それとも属性の名前だけ記述するので、余計ってことでしょうか? cardsを複数作るようにして、paramsの中身を見れば解は得られると思います。 が、cardsの数を動的に行うのは厳しいと思うので、2つ分のcardなど数を決めうちでやることをお勧めします。 そうやってステップを作って、確実に仕様を理解していくことをお勧めします。Railsが動くのでRailsで動かして反応を見るのが何よりも信頼できるし、紛れもない事実です。 頑張ってください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問