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

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

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

SlimはPHPアプリケーションを開発するための軽量なマイクロフレームワークです。

Ruby on Rails 7

Ruby on Rails 7は、2021年12月に正式リリースされました。Ruby on Railsのバージョン7であり、フロントエンド開発環境を大幅に刷新。Node.jsを用いない構成がデフォルトになっています。

Q&A

解決済

1回答

296閲覧

【Rails】中間テーブルで関連づけられた各モデルに同時にデータ保存したい

nanananan

総合スコア7

Slim

SlimはPHPアプリケーションを開発するための軽量なマイクロフレームワークです。

Ruby on Rails 7

Ruby on Rails 7は、2021年12月に正式リリースされました。Ruby on Railsのバージョン7であり、フロントエンド開発環境を大幅に刷新。Node.jsを用いない構成がデフォルトになっています。

1グッド

1クリップ

投稿2023/09/28 23:27

編集2023/09/29 05:22

お世話になっております。

下記サイト様のモデル設計を参考にして、ユーザー新規登録時の入力フォーム経由でUser、Group(中間テーブル)、Familyの複数モデルで同時にデータ保存できるようにしたいです。

参考サイト様
https://qiita.com/tak8_al/items/08274dd9228363642555

またデータ保存をしたい各モデルの内容は下記の通りです。

・Userモデル

  • id
  • name
  • email
  • password_digest

・Groupモデル(中間テーブル)

  • id
  • family_id
  • user_id

・Familyモデル

  • name

初歩的な質問をしてしまい大変恐縮ですが、ご助言いただけますと幸いです。
どうぞよろしくお願いいたします。

実現したいこと

  • ユーザー新規登録時に、Group、Familyモデルのデータ保存が同時に行えるようにしたい

前提

前提として家族で育児記録を共有できる仕様にしたいと考え、家族関係にあるユーザーを紐づけるべく、中間テーブルとしてGroupモデルを作成しました。

また参考サイト様ではFamilyモデルを用意してのちにFamilyモデルとPetモデル(私の場合ではChildモデル予定)を紐づけるデータベース設計だったので、新たにFamilyモデルを追加しました。

しかし中間テーブルを含めた複数モデルでのデータ保存の方法を今ひとつ理解できておらず、質問させていただきました。

【追記】
コメントにて参考サイトの情報が古く理解の妨げになるとのご指摘をいただきまして、参考サイト様をRailsガイドへと変更させていただきました。

参考サイト様
https://railsguides.jp/form_helpers.html#%E8%A4%87%E9%9B%91%E3%81%AA%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B

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

コンソール上でUnpermitted parameters: :user_id, :group, :family.とあることからストロングパラメータ内の問題と理解しましたが、どのように変更すればいいのかがわかっておりません。

またfamily_idというGroupモデルの外部キーをどのように取得すればいいのか、入力フォームでの取り方自体がまず間違っている点も問題だと考えております。

terminal

1Started POST "/admin/users" for ::1 at 2023-09-29 13:46:35 +0900 2Processing by Admin::UsersController#create as TURBO_STREAM 3 Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"name"=>"ユーザーF", "email"=>"f@example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "user_id"=>"1", "group"=>{"group_id"=>""}, "family"=>{"name"=>"サンプル"}}, "commit"=>"登録する"} 4 5Unpermitted parameters: :user_id, :group, :family. Context: { controller: Admin::UsersController, action: create, request: #<ActionDispatch::Request:0x000000010dc2ec38>, params: {"authenticity_token"=>"[FILTERED]", "user"=>{"name"=>"ユーザーF", "email"=>"f@example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "user_id"=>"1", "group"=>{"group_id"=>""}, "family"=>{"name"=>"サンプル"}}, "commit"=>"登録する", "controller"=>"admin/users", "action"=>"create"} } 6 TRANSACTION (0.1ms) BEGIN 7 ↳ app/controllers/admin/users_controller.rb:15:in `create' 8 User Exists? (0.7ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "f@example.com"], ["LIMIT", 1]] 9 ↳ app/controllers/admin/users_controller.rb:15:in `create' 10 11 TRANSACTION (0.1ms) ROLLBACK 12 ↳ app/controllers/admin/users_controller.rb:15:in `create' 13 Rendering layout layouts/application.html.slim 14 Rendering admin/users/new.html.slim within layouts/application 15 User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]] 16 ↳ app/controllers/application_controller.rb:8:in `current_user' 17 Rendered admin/users/_form.html.slim (Duration: 2.5ms | Allocations: 6987) 18 Rendered admin/users/new.html.slim within layouts/application (Duration: 2.6ms | Allocations: 7176) 19 CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]] 20 ↳ app/controllers/application_controller.rb:8:in `current_user' 21 Rendered layout layouts/application.html.slim (Duration: 5.9ms | Allocations: 14075) 22Completed 422 Unprocessable Entity in 312ms (Views: 5.9ms | ActiveRecord: 10.4ms | Allocations: 30071)

該当のソースコード

【追記】参考サイト様の情報をもとに主にコントローラ周りを編集しましたが、バリデーションによるエラーメッセージとして、Groups familyを入力してくださいとusers#newビュー画面上に表示されている状況です。

各種モデルアソシエーション設定

app/models/famiry.rb

1class Family < ApplicationRecord 2 has_many :groups, dependent: :destroy 3 has_many :users, through: :groups, source: :user 4end

app/models/group.rb

1class Group < ApplicationRecord 2 belongs_to :family 3 belongs_to :user 4end

【追加】userモデル内に、Familyモデルに関するaccepts_nested_attributes_forの設定を追記しました。

app/models/user.rb

1class User < ApplicationRecord 2 has_many :groups, dependent: :destroy 3 has_many :families, through: :groups, source: :family 4 accepts_nested_attributes_for :groups, allow_destroy: true 5 accepts_nested_attributes_for :families, allow_destroy: true 6end

usersコントローラ
【追加】ストロングパラメータ内設定を変更しました。

app/controllers/users_controller.rb

1def create 2 @user = User.new(user_params) 3 @user.groups.build 4 5 if @user.save 6 redirect_to root_path, notice: "「#{@user.name}」さんを登録しました" 7 else 8 render :new, status: :unprocessable_entity 9 end 10end 11 12private 13 14 def user_params 15 params.require(:user).permit(:name, :email, :password, :password_confirmation, groups_attributes: [:id, :user_id, :family_id], families_attributes: [:id, :name]) 16 end

ユーザー新規登録時入力フォームビュー
【追加】ネストした入力フォームのGroupモデルに関するhidden_field設定を変更しました。

app/views/admin/users/_form.html.slim

1= form_with model: @user, url: admin_users_url, local: true do |f| 2 3 .form-group 4 = f.label :name 5 = f.text_field :name, class: 'form-control' 6 7 .form-group 8 = f.label :email 9 = f.text_field :email, class: 'form-control' 10 11 .form-group 12 = f.label :password 13 = f.password_field :password, class: 'form-control' 14 15 .form-group 16 = f.label :password_confirmation 17 = f.password_field :password_confirmation, class: 'form-control' 18 19 = f.hidden_field :user_id, :value => current_user.id 20 21 = f.fields_for :group do |g| 22 = g.hidden_field :family_id 23 24 = f.fields_for :family do |ff| 25 = ff.label :name 26 = ff.text_field :name 27 28 = f.submit '登録する', class: 'btn btn-primary'

試したこと

  • accepts_nested_attributes_forによる複数モデルのデータ保存
  • fields_for使用での入力フォームのネスト
  • 各モデルのアソシエーション見直し

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

  • ruby 3.1.2p20
  • Rails 7.0.6
shinoharat👍を押しています

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

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

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

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

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

shinoharat

2023/09/29 04:29 編集

申し上げにくいのですが、そもそも参考にされているサイト( https://rails.densan-labs.net/ )の情報があまり良くないと思います。 最終更新が5年前・対象バージョンRails4.1 とかなり古い上、それぞれの model を継承した Form::Xxxxx を作るなど独特な実装が含まれていて、理解の妨げになっているのではないでしょうか。 余力があれば「Rails ガイド」などの、新しくて信頼できる情報を基に作り直した方が良い気がしますがどうですか? [Rails ガイド] > [Action View フォームヘルパー] > [10. 複雑なフォームを作成する] https://railsguides.jp/form_helpers.html#%E8%A4%87%E9%9B%91%E3%81%AA%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B
nanananan

2023/09/29 04:51

まずはコメントいただき、ありがとうございます。 自身で実装するにあたり、参考サイト様の最終更新が5年前というところまで確認が及んでおりませんでした。 今回添付いただきましたRailsガイドを参照した上でコントローラ、モデル設定を変更させていただいたところ、新たにエラーが発生している次第です。 当初ご質問させていただきました内容と状況が異なりますので、質問内容を改めて編集させていただきます。 ご指摘いただきまして、ありがとうございます。
matsubokkuri

2023/09/29 23:39

app/models/famiry.rb typoかなと。 `family.rb`
nanananan

2023/10/09 00:35

気付くのが遅くなってしまい、申し訳ございません。 タイプミスをご指摘いただいておりました'famiry.rb'ですが、実際のファイル名は'family.rb'になっておりました。 質問時点でのタイプミスのため、ファイル名は変更しておりません。 今後は質問時点にもタイプミスをしないよう気をつけます。 ご指摘いただき、ありがとうございました。
guest

回答1

0

ベストアンサー

結論

Groupのレコードを入れるためにはFamilyを先に作らないといけませんが、今書いてあるActiveRecordではそのような関連性を表現できていないからです。

ControllerでFamilyをcreateしてから、Groupをcreateすればできると思います。もちろん、排他制御ブロック内で。

そもそも

今のUIですと、Userを登録する際にFamilyの新規作成が必須になるようなUIなので要件がいまいちなところもあります。

その他の大きなところの指摘

やろうとしていることはHABTMモデルですね。(N:Mの関連性です)
よって、モデルは has_and_belongs_to_many で関連付けたほうがより適切です。

その他の小さなところの指摘

1. モデルの修正

app/models/famiry.rb のファイル名が famiry となっていますが、これは family の間違いではないでしょうか? ファイル名とクラス名を修正する必要があります。

2. フォームの修正

hidden_field :user_id は不要で、これは自動的に設定されます。また、Group の family_id はフォームを介して設定するのではなく、コントローラで設定することが一般的です。

3. コントローラの修正

@user.groups.build を使っているのですが、この部分は正確には不要で、また、family_id をこの時点で設定するのは不適切です。フォームから渡されたパラメータを利用して Family を先に作成し、その ID を使用して Group を作成する流れが自然です。

4. ストロングパラメータの修正

user_id と family_id をストロングパラメータで許可する必要はありません。これらは自動的に設定またはコントローラ内で設定すべき値です。

投稿2023/09/29 23:50

matsubokkuri

総合スコア744

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

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

nanananan

2023/10/03 05:05

お世話になっております。 まずはご回答いただき、誠にありがとうございます。 また返信が遅くなりまして、申し訳ございません。 ユーザー新規登録時のUIがfamilyの登録必須になっているとご指摘いただき、指摘されてからUI設計に無理があったことを理解いたしました。ありがとうございます。 ひとまずご指摘いただきました内容が複数点ございましたので、下記にて変更点および修正部分の詳細を記載させていただきました。 1.ユーザー新規登録画面よりfamilyモデルの記述削除 →families#newにて別途familyモデルのnameカラムを登録できるように設計変更したため、ユーザー新規登録画面からfamilyモデルの入力フォームは削除しました。 2.モデルの関連付けをhas_and_belongs_to_many に変更 →ご指摘いただきhas_and_belongs_to_manyのことを調べ直し、familyおよびusersモデルを下記関連づけに変更しました。 app/models/family.rb has_and_belongs_to_many :users app/models/users.rb has_and_belongs_to_many :families また上記関連づけを使用する際の一定のルールがあることを知り、下記のとおりに修正しました。 ・groupモデル削除 ・families_usersモデル作成 マイグレーションファイル class CreateFamiliesUsers < ActiveRecord::Migration[7.0] def change create_table :families_users, id: false do |t| t.bigint :family_id, null: false t.bigint :user_id, null: false end add_index :families_users, :family_id add_index :families_users, :user_id end end 3.モデルファイル名の確認 →確認したところ、famiryモデルというのは質問時点で打ち間違えていただけでした。 実ファイル名はfamily.rbであったため、こちらは変更なしです。お手間をとらせてしまい、申し訳ございません。 4.usersコントローラの修正 →@user.group.build、およびfamily_id部分の設定削除 5.ストロングパラメータ修正 →user_idおよびfamily_idの記述削除 ユーザー新規登録機能とfamilyモデル入力機能を分けたのちに機能を確認したところ、familyモデルのnameカラムは無事登録できるようになりました。 中間テーブルの持たせ方によってもデータの取り扱い方や設定方法などがこんなにも変わるものだと改めて再認識でき、とても勉強になりました。 誠にありがとうございます。 まだまだ勉強不足のため今後も必要に応じてご質問させていただきますので、その際はご指導よろしくお願いいたします。
matsubokkuri

2023/10/17 08:39

はい。 正しくHABTMの特性を理解していただいたようで良かったです。 コードをざっと見ましたが良さそうです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問