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

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

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

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

Q&A

解決済

1回答

1400閲覧

中間テーブルのdestroyアクションにidを渡せない

tarotarotarotar

総合スコア41

Ruby on Rails

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

0グッド

0クリップ

投稿2020/10/15 03:34

編集2020/10/15 16:03

現在お気に入り登録機能を作成しております。

存在しているテーブルは以下となります。(文章が長くなってしまうのでアソシエーションは正しく組んでいるものとさせていただきます。)

・Userテーブル
・Nutritionテーブル ※食材
・Favoriteテーブル(中間テーブル ※カラムはuser_idとnutrition_id)

userが気に入った食材があればお気に入りに登録できるという機能です。

お気登録ボタンと解除ボタンをindex/html.erbに実装しております。
登録はできるのですが、解除ボタンを押すとエラーとなります。

【表示されるエラー分】
ActionController::UrlGenerationError in Nutritions#index
Showing /Users/shotaro_hosoda/projects/berries/app/views/nutritions/index.html.erb where line #38 raised:

No route matches {:action=>"destroy", :controller=>"favorites", :nutrition_id=>27, :user_id=>3}, missing required keys: [:id]
Extracted source (around line #38):

<%= link_to "登録", user_favorites_path(user_id:current_user.id, nutrition_id:nutrition.id), method: :post %> <% else %> ↓エラー箇所ーーーーー <%= link_to "解除", favorite_path(user_id:current_user.id, nutrition_id:nutrition.id), method: :delete %> ーーーーーーーーーーー <% end %>

Favoriteテーブルの主キーを渡せていないことが原因かと思いますが主キーの定義の仕方がわかりません・・・
かなり初歩的な質問となってしまい、申し訳ございません。
この場合、中間テーブルの主キーになりますが、どうやって定義して引数として渡してあげればよいのでしょうか。(記述してあるのは外部キーである、user_idとnutrition_idを渡してfind_byでdeleteしようとあがいているコードです)

-----------以下コードーーーーーーーーーーーーーーーーーー

【ビュー】index.html.erb
登録されていれば解除ボタン表示、登録されていなければ登録ボタンを表示

<%= form_with(url: search_nutritions_path, local: true, method: :get, class: "search-form") do |form| %> <%= form.text_field :keyword, placeholder: "食品名を入力", class: "search-input" %> <%= form.submit "Search", class: "search-btn" %> <% end %> <script src="delete.js"></script> <div class='main-contents'> <h1 class="contents-title">食品一覧(100gあたり)</h1> <table border="5" width="80%" cellpadding="20" bordercolor="#882d91" class="contents-column" align="left"> <tr class="column-name"> <th width="30%" height="50">食品名</th> <th class="column-color1" width="15%">エネルギー(kcal)</th> <th class="column-color1" width="15%">タンパク質(g)</th> <th class="column-color1" width="15%">脂質(g)</th> <th class="column-color1" width="15%">炭水化物(g)</th> <th class="column-color2" width="15%">カリウム(mg)</th> <th class="column-color2" width="15%">カルシウム(mg)</th> <th class="column-color2" width="15%">鉄(mg)</th> <th class="column-color3" width="15%">ビタミンA(mg)</th> <th class="column-color3" width="15%">ビタミンB1(mg)</th> <th class="column-color3" width="15%">ビタミンB2(mg)</th> <th class="column-color3" width="15%">ビタミンC(mg)</th> <th width="15%">食塩相当量(g)</th> <th width="15%">登録ユーザー</th> </tr> <% @nutritions.each do |nutrition| %> <tr height="60" class="content-post"> <td class="ingredient-column" id="ingredient-column"><%= nutrition.ingredient %> <div class="more" id="more"> <ul class="more-list" id="more-list"> <li> <% if current_user.already_favorited?(nutrition) %> <%= link_to '解除', nutrition_favorite_path(id:favorite.id, user_id:current_user.id, nutrition_id:nutrition.id), method: :delete %> <% else %> <%= link_to '登録', edit_nutrition_path(nutrition.id), method: :get %> <% end %> <%= link_to '編集', edit_nutrition_path(nutrition.id), method: :get %> <%= link_to '削除', nutrition_path(nutrition.id), method: :delete, data: { confirm: '削除しますか?'} %> </li> </ul> </div> </td> <td><%= nutrition.calorie %></td> <td><%= nutrition.protein %></td> <td><%= nutrition.lipid %></td> <td><%= nutrition.carbohydrate %></td> <td><%= nutrition.potassium %></td> <td><%= nutrition.calcium %></td> <td><%= nutrition.iron %></td> <td><%= nutrition.vitamin_a %></td> <td><%= nutrition.vitamin_b1 %></td> <td><%= nutrition.vitamin_b2 %></td> <td><%= nutrition.vitamin_c %></td> <td><%= nutrition.salt_equivalent %></td> <td><%= nutrition.user.nickname %></td> </tr> <% end %> </table> </div>

【ルーティング】routes.rb

Rails.application.routes.draw do devise_for :users # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html root to: 'nutritions#index' resources :nutritions do collection do get 'search' end member do post "add", to: "favorites#create" end resource :favorites, only: [:destroy] end resources :users do resources :favorites, only: [:show, :create] end end

【コントローラー】favorites_controller.rb

class FavoritesController < ApplicationController def show @nutritions = current_user.nutritions @user = User.find(params[:id]) @favorites = Favorite.where("user_id = ?", @user) end def create @user_id = current_user.id @nutrition_id = Nutrition.find(params[:nutrition_id]) @favorite = Favorite.new(nutrition_id: @nutrition_id.id, user_id: @user_id) if @favorite.save! redirect_to root_path end end def destroy @favorite = Favorite.find_by(user_id:current_user.id, nutrition_id:params[:nutrition_id]) if @favorite.destroy redirect_to root_path end end private def favorite_params params.require(:favorite).permit(:user_id, :nutrition_id) end end

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

ご教授よろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

中略になっているので詳細にどんなパラメータを渡せばいいか定かではないですが、 missing required keys: [:id]と言われているので少なくともidを渡す必要があります。

Favoriteテーブルの主キーを渡せていないことが原因かと思いますが主キーの定義の仕方がわかりません

とのことで以下のように、するとidを渡せるかと思います。

favorite_path(id: favorite.id, user_id:current_user.id, nutrition_id:nutrition.id)

実際のコードの中でfavoriteが定義されていなくてとかは起きそうですが、動作だけなら例えば favorite.idの部分をひとまず1とか適当な値をいれてしまってもいいかもです。

そもそもpathにidがいらないならば、 resource :favorites, only: [:destroy]とresourcesではなくresourceと定義するのも解決策となりうるかもです。

投稿2020/10/15 13:59

hatsu

総合スコア1809

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

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

tarotarotarotar

2020/10/16 04:19 編集

ありがとうございます!数字だけ入れてみましたら動作はしました! しかし、やはりfavoriteが定義されておらずエラーになります。 以下エラー文です NameError in Nutritions#index Showing /Users/shotaro_hosoda/projects/berries/app/views/nutritions/index.html.erb where line #39 raised: undefined local variable or method `favorite' for #<#<Class:0x00007fcca560a440>:0x00007fcc9b83e2c0> favoriteをどう定義すればいいのかどうしても思いつきません・・・ ビューで呼び出しているindexコントローラーでインスタンスを生成するのかなとはなんとなく思いつきますが、中間テーブルのインスタンスを生成方法が??です???? 調べてみると今回のケースのように直接中間テーブルの主キーを渡してdeleteしているケースは見当たらず、@nutritionとかでdeleteできている記事ばかりで同じようにやっても上手く行かないんです・・・ 今回のコントローラーの中のdeleteアクション内で@favoriteを生成しており、必要なのはuser_idとnutrition_idで条件は満たしていると思うのですが・・・ ルーティングは以下になってます。 nutrition_favorite DELETE /nutritions/:nutrition_id/favorites/:id(.:format) favorites#destroy ルーティングでfavoriteのidを求められているんでしょうか? ネストの仕方を間違えている? 色々と考えて試しましたがどうしても解決できません・・・ 教えていただけますと幸いです。 コードは全て記載し直しました。
hatsu

2020/10/16 01:48

>ルーティングでfavoriteのidを求められているんでしょうか? はい、favorites/:id と書かれているので求められています。 >ネストの仕方を間違えている? どういう仕様にするかの問題です。 例えば PostID1番のデータを消したいときに、/posts/1(=/posts/:id) がDeleteアクションに対応しているのは自然です。 今回のようにFavoriteを削除する際にも、user_idとnutrition_idがあればfavorite.idはいらないのであれば resources :users do resources :favorites, only: [:show, :create] resource :favorites, only: [:destroy] end のように定義したらいかがでしょうか
tarotarotarotar

2020/10/16 04:24

ありがとうございます! ご教示頂いたことを一通り試しましたが上手く行かず、他に原因があると考えます。 これ以上お手間取らせていただくわけには行かないので 一旦、主キーをテキトーにid:0でdestroyアクションに渡してあげて 削除の際は @favorite = Favorite.find_by(user_id:current_user.id, nutrition_id:params[:nutrition_id]) @favorite.destroy と主キーは使わずに削除するという応急処置で動作するようになったので一旦これで進めたいと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問