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

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

ただいまの
回答率

88.31%

ActionController::UrlGenerationError(いいねボタンのmethod:delete)

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 359

解決したいこと

  • いいね機能を実装中です。その際、いいねボタンを押すと、ActionController::UrlGenerationErrorが出て、トップページを表示できなくなってしまいました。
  • method: :delet(エラー画面の指定箇所)をコメントアウトすると、「いいねしたユーザー」が正しく表示されます。ですので、javascriptの関係のエラーかと思ったのですが、javascript_pack_tagを使用しているのと、投稿削除のdeleteメソッドは正しく作動しているので、原因がわかりませんでした。
  • すみませんがどなたか分かる方いらっしゃいましたら、ご教授お願いします。

試したこと

  • 【tweets > index.heml.haml】= button_to 'いいねを取り消す', tweet_like_path(tweet), method: :deleteの部分を = button_to 'いいねを取り消す', tweet_like_path(tweet,like), method: :deleteに変更
    →NAME ERROR undefined local variable or method `like'

  • 【tweets_controller.rb】の

def index
    @tweets = Tweet.includes(:user).order("created_at DESC")
    @like = Like.new
end

↓↓↓を下記に変更↓↓↓

def index
    @tweets = Tweet.includes(:user,:like).order("created_at DESC")
    @like = Like.new
  end

→ActiveRecord::AssociationNotFoundErrorになってしまいました。

環境

rails 6.0.0 "haml-rails", ">= 1.0", '<= 2.0.1' 'pg', '>= 0.18', '< 2.0'

参考記事

https://qiita.com/nojinoji/items/2c66499848d882c31ffa

関連のする箇所

エラー画面

イメージ説明

実行時のターミナル

Started GET "/tweets" for ::1 at 2020-07-30 23:55:11 +0900
Processing by TweetsController#index as HTML
  Rendering tweets/index.html.haml within layouts/application
  Tweet Load (1.0ms)  SELECT "tweets".* FROM "tweets" ORDER BY created_at DESCapp/views/tweets/index.html.haml:3
  User Load (0.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1  [["id", 1]]
  ↳ app/views/tweets/index.html.haml:3
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/views/tweets/_tweet.html.haml:9
  Tag Load (0.7ms)  SELECT "tags".* FROM "tags" INNER JOIN "tweet_tag_relations" ON "tags"."id" = "tweet_tag_relations"."tag_id" WHERE "tweet_tag_relations"."tweet_id" = $1  [["tweet_id", 7]]
  ↳ app/views/tweets/_tweet.html.haml:19
  Like Exists? (0.6ms)  SELECT 1 AS one FROM "likes" WHERE "likes"."user_id" = $1 AND "likes"."tweet_id" = $2 LIMIT $3  [["user_id", 1], ["tweet_id", 7], ["LIMIT", 1]]
  ↳ app/models/user.rb:11:in `already_liked?'
  Rendered tweets/_tweet.html.haml (Duration: 19.4ms | Allocations: 4272)
  Rendered tweets/index.html.haml within layouts/application (Duration: 35.9ms | Allocations: 6190)
Completed 500 Internal Server Error in 47ms (ActiveRecord: 3.3ms | Allocations: 6799)



ActionView::Template::Error (No route matches {:action=>"destroy", :controller=>"likes", :tweet_id=>#<Tweet id: 7, name: nil, text: "あ", image: "f3072d14ccf044ef823aeb8538ae3ced.jpg", created_at: "2020-07-30 04:13:59", updated_at: "2020-07-30 04:13:59", user_id: 1>}, missing required keys: [:id]):
    21:   %h3
    22:     -# いいね件数: #{@tweet.likes.count}
    23:   - if current_user.already_liked?(tweet)
    24:     = button_to 'いいねを取り消す', tweet_like_path(tweet), method: :delete
    25:   - else
    26:     = button_to 'いいね', tweet_likes_path(tweet)
    27:   %h2 いいねしたユーザー

app/views/tweets/_tweet.html.haml:24
app/views/tweets/index.html.haml:4
app/views/tweets/index.html.haml:3

ビューファイル

tweet.html.haml
%main.Index
  %section.TweetField
    - @tweets.each do |tweet|
      %article.PostedItem
        .ArticleHeader
          %ul.More
            %li 
              = icon('fas', 'bars')
              %ul
                %li
                  = link_to '詳細', tweet_path(tweet.id), method: :get
                - if user_signed_in? && current_user.id == tweet.user_id
                  %li
                    = link_to '編集', edit_tweet_path(tweet.id), method: :get
                  %li
                    = link_to '削除', tweet_path(tweet.id), method: :delete

        .Picture
          .content_post{style: "background-image: url(#{tweet.image})"}
        .ReactionBtn
          = icon('fas', 'star', class: 'ReactionBtn__good')
          - tweet.tags.each do |tag|
            = tag.tag_name
        %h3
        - if current_user.already_liked?(tweet)
          = button_to 'いいねを取り消す', tweet_like_path(tweet),method: :delete
        - else
          = button_to 'いいね', tweet_likes_path(tweet)
        %h2 いいねしたユーザー
        - tweet.liked_users.each do |user|
          %li= user.email
        = link_to "ホームへ戻る", tweets_path

コントローラー

tweets_controller.rb
class TweetsController < ApplicationController
  before_action :set_tweet, only: [:edit, :show]
  before_action :move_to_index, except: [:index, :show, :search]
  before_action :authenticate_user!, only: [:show, :create]

  def index
    @tweets = Tweet.includes(:user).order("created_at DESC")
  end

  def new
    @tweet = Tweet.new
  end

  def create
    @tweet = Tweet.create(tweet_params)
    @tweet.user_id = current_user.id

  end

  def destroy
    tweet = Tweet.find(params[:id])
    tweet.destroy
  end

  def edit
  end

  def update
    tweet = Tweet.find(params[:id])
    tweet.update(tweet_params)
  end

  def show
    @like = Like.new
    @comment = Comment.new
    @comments = @tweet.comments.includes(:user)
  end

  def search
    @tweets = Tweet.search(params[:keyword])
  end

  private
  def tweet_params
    params.require(:tweet).permit(:image, :text).merge(user_id: current_user.id)
  end

  def set_tweet
    @tweet = Tweet.find(params[:id])
  end

  def move_to_index
    unless user_signed_in?
      redirect_to action: :index
    end
  end

  def tag_params
    params.require(:tweet).permit(:tag_names)
  end
end
likes_controller.rb
class LikesController < ApplicationController
  def create
    @like = current_user.likes.create(tweet_id: params[:tweet_id])
    redirect_back(fallback_location: root_path)
  end

  def destroy
    @like = Like.find_by(tweet_id: params[:tweet_id], user_id: current_user.id)
    @like.destroy
    redirect_back(fallback_location: root_path)
  end
end

モデル

tweet.rb
class Tweet < ApplicationRecord
  validates :text, presence: true
  belongs_to :user
  has_many :comments
  has_many :tweet_tag_relations, dependent: :destroy
  has_many :tags, through: :tweet_tag_relations
  has_many :likes
  has_many :liked_users, through: :likes, source: :user

def liked_by?(user)
  likes.where(user_id: user.id).exists?
end
  def save_tags(tag_list)
    tag_list.each do |tag|
      unless find_tag = Tag.find_by(tag_name: tag.downcase)
        begin
          self.tags.create!(tag_name: tag)
        rescue
          nil
        end
      else
        TweetTagRelation.create!(tweet_id: self.id, tag_id: find_tag.id)
      end
    end
  end
  def self.search(search)
    if search
      Tweet.where('text LIKE(?)', "%#{search}%")
    else
      Tweet.all
    end
  end
end
tag.rb
class Tag < ApplicationRecord
  before_save :downcace_tag_name

  has_many :tweet_tag_relations, dependent: :destroy
  has_many :tweets, through: :tweet_tag_relations

  validates :tag_name, presence: true, uniqueness: true, length: { maximum: 50 }

  private
  def downcase_tag_name
    self.tag_name.downcase!
  end
end
tweet_tag_relation.rb(中間テーブル)
class TweetTagRelation < ApplicationRecord
  belongs_to :Tweet
  belongs_to :tag
end

ルーティング

routes.rb
Rails.application.routes.draw do
  devise_for :users
  root to: 'tweets#index'

  resources :users, only: :show
  resources :tweets do
    resources :likes, only: [:create, :destroy]
    resources :comments, only: :create
    collection do
      get 'search'
    end
  end
end

マイグレーションファイル

2020XXX_create_like.rb
class CreateLikes < ActiveRecord::Migration[6.0]
  def change
    create_table :likes do |t|
      t.references :user, null: false, foreign_key: true
      t.references :tweet, null: false, foreign_key: true

      t.timestamps
    end
  end
end
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • winterboum

    2020/07/31 05:31

    routes.rb を

    キャンセル

  • KotaTakahashi

    2020/07/31 08:38

    routes.rbを追加しました。お願いします。

    キャンセル

回答 1

0

削除するのは Tweetではなく likeですから、likeも渡さすひつようがあります。tweet_like_path(tweet) ⇒ tweet_like_path(tweet,like)
そのlikeをview上で得るが嫌で、今のcotrollerの様にdestroyで特定するのでしたら、tweet.idだけを受け取る routesを新たに定義が必要です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/31 13:45

    理解度が低くて申し訳ないです。
    tweet_like_pathで指定されているのは、likes#destroyなので、likesコントローラーの@like = current_user.likes.create(tweet_id: params[:tweet_id])のlikeという認識で間違い無いでしょうか。

    キャンセル

  • 2020/07/31 16:44

    @like = Like.find_by(tweet_id: params[:tweet_id], user_id: current_user.id)
    こっちでないの?

    キャンセル

  • 2020/07/31 16:54

    すみません間違えました。そちらだと思います。

    キャンセル

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

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

関連した質問

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