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

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

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

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

Q&A

解決済

1回答

861閲覧

タグのついた投稿記事を削除したい

tamtamtime

総合スコア8

Ruby on Rails 6

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

1グッド

1クリップ

投稿2023/01/18 07:17

前提

画像投稿のwebアプリをRuby on Rails6にて作成中です。
画像にはタグが付いており、削除時にエラーが出ます。

実現したいこと

投稿を削除したい

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

NoMethodError in DesignsController#destroy undefined method `find' for PostForm:Class

該当のソースコード

ruby

1def destroy 2 post_form = PostForm.find(params[:id]) 3 if post_form.destroy 4 redirect_to root_path 5 end

ruby

1[app > controller.rb] 2 3class DesignsController < ApplicationController 4 before_action :authenticate_user!, only:[:edit, :new, :destroy] 5 before_action :move_to_index, except: [:index, :show] 6 before_action :set_design, only: [:show, :edit] 7 8 def index 9 @designs = Design.includes(:user).order("created_at DESC") 10 end 11 12 def new 13 @post_form = PostForm.new 14 end 15 16 def create 17 @post_form = PostForm.new(design_params) 18 19 if @post_form.save 20 redirect_to root_path 21 else 22 render :new 23 end 24 end 25 26 def show 27 28 end 29 30 def destroy 31 post_form = PostForm.find(params[:id]) 32 if post_form.destroy 33 redirect_to root_path 34 end 35 end 36 37 def update 38 design = Design.find(params[:id]) 39 if 40 design.update(design_params) 41 redirect_to design_path(design.id) 42 else 43 redirect_to request.referer 44 end 45 end 46 47 def edit 48 unless user_signed_in? && current_user.id == @design.user_id 49 redirect_to action: :index 50 end 51 end 52 53 def search 54 @designs = Design.search(params[:keyword]).order("created_at DESC") 55 end 56 57 private 58 59 def design_params 60 params.require(:post_form).permit(:title, :file_name, :tag_name, :image).merge(user_id: current_user.id) 61 end 62 63 def set_design 64 @design = Design.find(params[:id]) 65 end 66 67 def move_to_index 68 unless user_signed_in? 69 redirect_to action: :index 70 end 71 end 72 73end 74

ruby

1[app > views > designs > show.erb] 2 3<main class="main"> 4 <div class="inner"> 5 <div class="prototype__wrapper"> 6 <p class="prototype__hedding"> 7 <%= @design.title %> 8 </p> 9 <% if user_signed_in? && current_user.id == @design.user_id %> 10 <div class="prototype__detail"><br> 11 <p class="detail__title">ファイル場所</p> 12 <p class="detail__message"> 13 <%= @design.file_name %> 14 </p> 15 </div> 16 <div class="prototype__manage"> 17 <%# link_to "編集する", edit_design_path, method: :get, class: :prototype__btn %> 18 <%= link_to "削除する", design_path, method: :delete, class: :prototype__btn %> 19 </div> 20 <% end %> 21 22 <span class="tag_style">#<%=link_to @design.tags.first&.tag_name, search_designs_path(tag_id: tag.id)%></span> 23 24 <div class="prototype__image"> 25 <%= image_tag @design.image %> 26 </div> 27 28 </div> 29 </div> 30</main> 31

ruby

1[app > models > post_form.rb] 2 3class PostForm 4 include ActiveModel::Model 5 6 attr_accessor( 7 :title, :file_name, :image, 8 :id, :user_id, 9 :tag_name 10 ) 11 12 with_options presence: true do 13 validates :title 14 validates :file_name 15 validates :image 16 end 17 18 19 ActiveRecord::Base.transaction do 20 21 def save 22 design = Design.create!(title: title, file_name: file_name, image: image, user_id: user_id) 23 tag = Tag.where(tag_name: tag_name).first_or_initialize 24 tag.save! 25 PostTagRelation.create!(design_id: design.id, tag_id: tag.id) 26 end 27 28 29 30 return true 31 32 rescue false 33 end 34end 35

試したこと

def destroyをpost_formに書いたり、@をつけたり
def destroy
design = Design.find(params[:id])
if design.destroy
redirect_to root_path
end
end
に書き換えてみたり、

find(params[:id]) を PostForm.(design_params) に変えてみても
param is missing or the value is empty: post_form のエラーが出るだけでした。

shinoharat👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

PostForm クラスには find メソッドも destroy メソッドも存在しないのに、その存在しないメソッドを呼び出そうとしているため、エラーが発生しています。

「試したこと」の

rb

1def destroy 2 design = Design.find(params[:id]) 3 if design.destroy 4 redirect_to root_path 5 end 6end

というコードが大正解なので、それで良いはずですが、動きませんか?
改めて実行してみて、エラーが出るならメッセージを教えてください。

--

追伸:
PostForm のトランザクションの書き方がおかしいので、ついでにそっちも直した方が良いと思います。

rb

1 # ↓ こう書くのが正しいです。 2 def save 3 ActiveRecord::Base.transaction do 4 design = Design.create!(title: title, file_name: file_name, image: image, user_id: user_id) 5 tag = Tag.where(tag_name: tag_name).first_or_initialize 6 tag.save! 7 PostTagRelation.create!(design_id: design.id, tag_id: tag.id) 8 end 9 10 return true 11 rescue 12 return false 13 end

--

追記:

エラー原因の解説

以下のエラーは「外部キー制約」に失敗しているために表示されます。

ActiveRecord::InvalidForeignKey in DesignsController#destroy
Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails

例えば、「デザインA」に「Tag: Ruby」と「Tag: Java」の2つが紐づいている場合、DBでは以下のようなデータ構造になります。

[designs]
| id | title |
| 11 | デザインA |

[post_tag_relations]
| id | design_id | tag_id |
| 1 |    11 |   21 |
| 2 |    11 |   22 |

[tags]
| id | tag_name |
| 21 | Ruby |
| 22 | Java |

ここで単純に「デザインAだけ」を消すと、 post_tag_relations テーブルに「存在しない design_id 」が発生してしまいます。

[post_tag_relations]
| id | design_id | tag_id |
| 1 |   ⚠️11 |   21 | ← 「存在しない ID を指し示すのはおかしくね?」とMySQL君が気をきかせる
| 2 |   ⚠️11 |   22 |

なので、そうならないようにエラーを発生させて、データの整合性を保とうとするわけです。
それが、エラーメッセージ「Cannot delete or update a parent row: a foreign key constraint fails」の意味です。

修正方法

単純に designs だけを消すのではなく、関連する post_tag_relations も一緒に消す必要があります。
コードの修正はすごく簡単で、モデル側に dependent: :destroy のオプションを付けるだけです。

diff

1 class Design < ApplicationRecord 2 belongs_to :user 3- has_many :post_tag_relations 4+ has_many :post_tag_relations, dependent: :destroy 5 has_many :tags, through: :post_tag_relations 6 has_one_attached :image 7 8 ・・・略・・・

投稿2023/01/18 08:25

編集2023/01/19 00:32
shinoharat

総合スコア1674

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

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

tamtamtime

2023/01/18 08:44

ご回答ありがとうございます!! def destroy design = Design.find(params[:id]) if design.destroy redirect_to root_path end end ですと以下のエラーが出ます。 ActiveRecord::InvalidForeignKey in DesignsController#destroy Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`abestdesign_development`.`post_tag_relations`, CONSTRAINT `fk_rails_c3aa21b013` FOREIGN KEY (`design_id`) REFERENCES `designs` (`id`)) Extracted source (around line #30): 28 def destroy 29 design = Design.find(params[:id]) 30 if design.destroy 31 redirect_to root_path 32 end 33 end IDが変だという事まではわかるのですが、記載が間違っているのかと右往左往してしまいました。
tamtamtime

2023/01/19 00:31

モデルに「dependent: :destroy」を追記で削除できるようになりました。 難しく考え過ぎたかもしれません。
shinoharat

2023/01/19 00:33

先ほど回答を更新したのですが、既に自己解決されてたみたいですね。 「dependent: :destroy」で大正解です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問