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

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

ただいまの
回答率

88.05%

1つのフォームで親レコードと複数の子レコードを保存したいが、accepts_nested_attributes_forが機能せずキー名が正しく表示されない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 865

score 37

前提・実現したいこと

一つのフォームでアソシエイトが組まれた2つのモデルを生成したい。
タイトルの通り、accepts_nested_attributes_forが正しく機能してくれません。
そこさえ解決すればあとは問題なく実装できると踏んでいます。

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

以下のページのように実装。
https://qiita.com/ftyabu/items/cae912b211e985d74d58
親モデルにあたるsongはDBに保存されるが、子モデルであるkeyは保存されない

該当のソースコード

Songモデル(親)

class Song < ApplicationRecord
  has_many :keys, dependent: :destroy
  accepts_nested_attributes_for :keys
  belongs_to :user
end


Keyモデル(子)

class Key < ApplicationRecord
  belongs_to :song
end


songコントローラのnewおよびcreateアクション

def new
  @song = Song.new
  @song.keys.build
end

def create
  @song = Song.new(song_params)

  respond_to do |format|
    if @song.save
      format.html { redirect_to @song, notice: 'Song was successfully created.' }
      format.json { render :show, status: :created, location: @song }
    else
      format.html { render :new }
      format.json { render json: @song.errors, status: :unprocessable_entity }
    end
  end
end


songコントローラのストロングパラメータ

def song_params
   params.permit(:title, :jam, :standard, :beginner, keys_attributes: [:name, :instrumental, :male, :female]).merge(user_id: current_user.id)
end


viewファイル

.contents__title
=form_with url: songs_path, class: "contents__form", method: :post, local: true do |f|
  .form--title
    = f.label "タイトル" do
      = f.text_field :title
  .form__class
    =f.label :jam, class: "class--element" do
      = f.check_box :jam, checked_value: "1", unchecked_value: "0"
      ジャムセッション向け曲
    =f.label :standard, class: "class--element" do
      = f.check_box :standard, checked_value: "1", unchecked_value: "0"
      スタンダード曲
    =f.label :beginner, class: "class--element" do
      = f.check_box :beginner, checked_value: "1", unchecked_value: "0"
      初心者向け曲
  .form__key
    =f.fields_for :keys do |key_f|
      .chord-menu
        .chord-menu__key
// 中略
    = f.submit "登録"

試したこと

  • accepts_nested_attributes_for :keysが機能しているか。
    28: def create
    29:   @song = Song.new(song_params)
    30:   binding.pry
 => 31:   respond_to do |format|
    32:     # 省略
    39:   end
    40: end

[1] pry(#<SongsController>)> params
=> <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"pOCRwVjfMP3Ku97oMWzWcZbKmULQAGyik+dEB/bVPpJPm0js+7rPkynSc1Ad8BvbH2y/pfbQLKLgovVMimnGfg==", "title"=>"why did you wonder", "jam"=>"0", "standard"=>"1", "beginner"=>"1", "keys"=>{"name"=>"key of G", "instrumental"=>"0", "male"=>"1", "female"=>"0"}, "commit"=>"登録", "controller"=>"songs", "action"=>"create"} permitted: false>


ネストはされているが、キー名がkeys_attributesではなく、keys

  • ストロングパラメータ中のpermitの中の値をkeysに変更
    「name(keysにネストされているキー名)はインスタンスのキーに存在しない」というニュアンスのエラーが発生しました。
    イメージ説明

  • 関係はなさそうだが、optional: trueやinverse_ofなどの記述も試す
    リスト エラーの原因がid違反でもvalidateでもないので関連はなさそうですが、以下のサイトの内容を試しました

  1. inverse_of
    https://qiita.com/Hiroyuki_OSAKI/items/bfb20c481e6c4970f415
  2. optional: true
    https://qiita.com/a-itabashi/items/6e0d4793996d887fd191

特に変化なし。キー名は相変わらずkeysのままでkeys_attributesにはなっていませんでした。

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

− ruby 2.5.1p57

  • rails (5.2.4.2)
  • haml (5.1.2)
  • haml-rails (2.0.1)
  • jbuilder (2.10.0)
  • mysql2 (0.5.3)
  • 他にjqueryとscssを併用しています。

これからfields_for以外の方法を試すつもりです。
かれこれ12時間ほど詰まっているので教えていただけると幸いです。

よろしくお願いいたします。

追記 試したこと

フォームで送るキー名を工夫

別画面で実装した際にも同様にaccepts_nested_attributes_forコマンドが機能しませんでした。
いっそ、フォームの方でごまかしせないか?と考えviewファイルを変更しました。field_forで送るキー名を変更してみました。

※別画面に実装しようとした際には、違うモデルを使っていますが混乱を避けるため、この質問で用いられるモデルに書き換えて、結果を表記します

viewファイル

//略
.form__key
  =f.fields_for :keys_attributes do |key_f|
//略


ストロングパラメータsong_paramsの出力は以下の通りです。

<ActionController::Parameters {"title"=>"why did you wonder", "jam"=>"0", "standard"=>"1", "beginner"=>"1", "keys_attributes"=><ActionController::Parameters {"name"=>"key of G", "instrumental"=>"0", "male"=>"1", "female"=>"0"} permitted: true>} permitted: false>


すると別のエラーメッセージが表示されました。
エラー画像
@tuning_allの行が

@song = Song.new(song_params)


にあたります。変数の型とは違う型を代入している際にでるエラーのようです。
accepts_nested_attributes_forは表面的に表示を変える以上の働きをしているのかな?と考えました。

フォームオブジェクトという初心者にはハードル高そうなものを使えば、accepts_nested~を使わなくても実装できるようなので、一度チャレンジしてみます。

accepts~で同じエラーが発生している記事を発見

Rails fields_for と accepts_nested_attributes_for を使うときの注意点
それって書き方変えただけじゃないの?というような内容ですが、わらにもすがる思いで真似してみましたが、結果変わらず。
内容を要約すると、

  • 子要素のモデルを作って送れているか?
  • accepts~のあとに記述したものと、field_forでつけたキー名が一致しているか?
    子要素のモデルに関してはfield_forのところで定義されていたので、私が親コントローラのnewアクションのところで記述していたものを同じように書いてためしました。念の為。

追記 シンプルな疑問

accepts〜の記述を受け付けないという事象は(原因は何にせよ、一般的に)そもそも発生し得ることなのでしょうか?
例えば○○Gemをbundle installしていないと機能しない、versionX.Xでは機能しない、など一定の条件下では反応しないことがありうるのでしょうか。
あり得る場合、エラーは発生するのでしょうか?それとも今起きているようにエラーは発生せず無視されるものなのでしょうか。

解決に直接至らなくてもそのあたりの切り分けがしたいので、情報があれば教えていただきたいと思っています。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • winterboum

    2020/05/24 02:40

    読めない(推理できない)んです。
    codeが断片的すぎる。
    肝心の keysのところが省略されている
    実際のmodelと違う名前の様だ

    なので、エラーが起きたのが載っているcodeの時なのかどうかも確信できなくなっている。

    質問書きなおしてください。
    何をしたか、は残して欲しいですが、controller、view、log/developpment.logのStarted POST から次のStartedまで
    を。
    実際のプログラムと名前を変えるなら全ての資料を確実に修正してください。
    @tuning_allの行が@song = Song.new(song_params)ですと言われても混乱するだけです。

    キャンセル

回答 1

check解決した方法

0

まっさらなところから再度書き出して、再度実行するとうまくいきました。
accepts_for〜文によってparamsに[子要素の複数形]_attributesというキーが正常に追加されました。

viewファイルが怪しいのですが、正直詳細は不明です。

うまく行ったコードとの差異としては

// before
=form_with url: songs_path, class: "contents__form", method: :post, local: true do |f|

// after
=form_with model: @song, url: songs_path, class: "contents__form", method: :post, local: true do |f|


のように親レコードのモデルを明記したところです。

疑っていたfields_forの記述の方は

f.fields_for :keys do |key_f|


と初期状態のままです。

同じ現象に陥った場合は試してみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.05%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • MySQLに関する質問
  • 1つのフォームで親レコードと複数の子レコードを保存したいが、accepts_nested_attributes_forが機能せずキー名が正しく表示されない