LoginSignup

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

rails 非同期いいね機能実装の際に発生したエラーで躓いてしまいました。 初心者です。

解決したいこと

エラーの解消と非同期いいねの実装

Ruby on RailsでTwitterのようなWebアプリをつくっています。
非同期いいね機能の実装中にエラーが発生しました。
解決方法を教えて下さい。

Rails 7.0.3
ruby 3.1.2
deviseなし

https://note.com/become_engineer/n/n45f7285622e3
上記の記事を参考に非同期いいねを導入しています。

発生している問題・エラー

.error
ActionController::UnknownFormat in LikesController#create
LikesController#create is missing a template for this request format and variant.
request.formats: ["text/html"]
request.variant: []

おそらくの原因

create.js.erb
$('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");
destroy.js.erb
$('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");

変更後

名前をjs -> html に変更すると反応するようになるという記事を見つけたので名前を変更しました。

create.html.erb
$('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");
destroy.html.erb
$('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");
.error
NoMethodError in Likes#create

undefined method `id' for nil:NilClass

            @virtual_path = "likes/create";;@output_buffer.safe_append='$(\'#likes_buttons_'.freeze;@output_buffer.append=( @post.id );@output_buffer.safe_append='\').html("'.freeze;@output_buffer.append=( j(render partial: 'likes/like', locals: {post: @post}) );@output_buffer.safe_append='");'.freeze;
                                                                                                                                 ^^^

$('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");(赤マーカー)
likes_controller.rb
class LikesController < ApplicationController
    before_action :authenticate_user
    before_action :post_params
    
    def create
      Like.create(user_id: @current_user.id, post_id: params[:id])
    end
    
    def destroy
      Like.find_by(user_id: @current_user.id, post_id: params[:id]).destroy
    end
    
  private
    
    def post_params
    end
end

本来

本来は下記のコードだったのですが、

likes_controller.rb
    def post_params
      @post = Post.find(params[:id])
    end

下記のようなエラーが出たため、とりあえず削除しました。

.error
ActiveRecord::RecordNotFound in LikesController#create
Couldn't find Post without an ID

次に

    before_action :post_params

上と下

  private
    def post_params
      @post = Post.find(params[:id])
    end

上記のコードを不要だと思い、削除すると下記のエラーが発生しました

.error
NoMethodError in Likes#create

undefined method `id' for nil:NilClass

            @virtual_path = "likes/create";;@output_buffer.safe_append='$(\'#likes_buttons_'.freeze;@output_buffer.append=( @post.id );@output_buffer.safe_append='\').html("'.freeze;@output_buffer.append=( j(render partial: 'likes/like', locals: {post: @post}) );@output_buffer.safe_append='");'.freeze;

$('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");

最後まで読んでいただきありがとうございます。
教えて頂けると幸いです。
よろしくお願いいたします。

0

2Answer

「本来」と「次に」で消したコードは必要なので戻してください。ファイル名の変更もたぶん不要です。

おそらくですが app/views/posts/index.html.erb の内容にミスがある気がします。コードを貼ってください。

2

Comments

  1. @NetaNeta0620

    Questioner

    返信いただきありがとうございます。

    何かわかると良いのですが
    何卒よろしくお願いいたします。

    index.html.erb
        <% @posts.each do |post| %>
          <div class="posts-index-item">
            <div class="post-left">
    
            <% if post.user.avatar? %>
              <%= link_to (image_tag post.user.avatar_url), "/users/#{post.user.id}" %>
            <% else %>      
              <%= link_to (image_tag src="default.jpg"), "/users/#{post.user.id}" %>
            <% end %> 
              
            </div>
            <div class="post-right">
              <div class="post-user-name">
                <%= link_to(post.user.name, "/users/#{post.user.id}") %>
              </div>
              <div class="post-title">
                <%= link_to(post.title.truncate(30), "/posts/#{post.id}") %>
              </div>
    ------------------------------------------------------------------------------------------------------------------------
              <div id="likes_buttons_<%= post.id %>">
                <%= render partial: 'likes/like', locals: {post: post} %>
              </div>
    ------------------------------------------------------------------------------------------------------------------------
              
              &emsp;
              
              <span class="fa fa-eye"></span>
              <%= post.view_counts.count if post.view_counts.count != 0 %>
              
              &emsp;
    
              <span class="fa fa-comment"></span>
              <%= @post_comments_count[post.id] %>
    
              <button id="share"><span class="fa fa-share-alt "></span></button>
              <script type="text/javascript">
                (function () {
                  function share() {
                    if (navigator.share) {
                      navigator.share({
                        title: '',
                        text: '',
                        url: '',
                      })
                        .then(() => {
                          // シェアしたら実行される
                          console.log('Successful share');
                        })
                        .catch((error) => {
                          // シェアせず終了した場合もここに入ってくる。
                          console.log('Error sharing', error)
                        });
                    } else {
                      alert('Web Share API is not supported!!');
                      // Web Share API未対応ブラウザ向けのフォールバックを実装する。
                    }
                  }
                  document.querySelector('#share').addEventListener('click', share);
                })();
              </script>    
                  
            </div>
          </div>
        <% end %>
    
    
  2. これだけだとまだ分からないので routes.rb と likes/_like.html.erb もお願いします。

  3. @NetaNeta0620

    Questioner

    了解しました。

    routes.rb
    Rails.application.routes.draw do
      get 'auth/:provider/callback' => 'sessions#create'
    
      resources :posts, only: [] do
        resources :comments
      end
    
      get 'searches' => 'posts#search'
    ------------------------------------------------------------------------------------------------------------------------
      get "likes/:post_id/create" => "likes#create", as: 'create_like'
      get "likes/:post_id/destroy" => "likes#destroy", as: 'destroy_like'
    ------------------------------------------------------------------------------------------------------------------------
      post "users/:id/update" => "users#update"
      get "users/:id/edit" => "users#edit"
      post "users/create" => "users#create"
      get "signup" => "users#new"
      get "users/index" => "users#index"
      get "users/:id" => "users#show"
      post "login" => "users#login"
      get "logout" => "users#logout"
      get "login" => "users#login_form"
    
      get "users/:id/likes" => "users#likes"
      get "users/:id/comments" => "users#comments"
    
      get "posts/index" => "posts#index"
      get "posts/new" => "posts#new"
      get "posts/:id" => "posts#show"
      post "posts/create" => "posts#create"
      get "posts/:id/edit" => "posts#edit"
      post "posts/:id/update" => "posts#update"
      get "posts/:id/destroy" => "posts#destroy"
      
      get "/" => "home#top"
      get "about" => "home#about"
    end
    
    likes/_like.html.erb
    <% if @current_user %>
     <% if @current_user.liked_by?(post.id) %>
       <td><%= link_to 'いいねを外す', destroy_like_path(post), method: :POST, remote: true %> <%= post.likes.count %></td>
     <% else %>
       <td><%= link_to 'いいね', create_like_path(post), method: :POST, remote: true %> <%= post.likes.count %></td>
     <% end %>
    <% end %>
    
    
  4. ルーティングが get "likes/:post_id/create" になっているので Post の id は params[:post_id] に入ります。 LikesController の中で params[:id] を参照している部分を params[:post_id] にすれば直ると思います。

  5. @NetaNeta0620

    Questioner

    ご指摘いただいたように変更したのですが、(下記)

    class LikesController < ApplicationController
        before_action :authenticate_user
        before_action :post_params
        
        def create
          Like.create(user_id: @current_user.id, post_id: params[:post_id])ここ
        end
        
        def destroy
          Like.find_by(user_id: @current_user.id, post_id: params[:post_id])ここ.destroy
        end
        
      private
        
        def post_params
          @post = Post.find(params[:post_id])ここ
        end
    end
    

    下記のエラーが出てしまいます。

    .error
    ActionController::UnknownFormat in LikesController#create
    LikesController#create is missing a template for this request format and variant.
    request.formats: ["text/html"]
    request.variant: []
    

    create.js.erbとdestroy.js.erbの名称はjsに戻した状態になっています。
    解消方法わかりますでしょうか?

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

  6.   get "likes/:post_id/create" => "likes#create", as: 'create_like'
      get "likes/:post_id/destroy" => "likes#destroy", as: 'destroy_like'
    

    この先頭の getpost にしてください。

  7. @NetaNeta0620

    Questioner

    routinguエラーが出てしまいました。
    viewとcontrollerを確認してみたのですが、原因わかりませんでした。
    何かわかりますでしょうか?

    Routing Error
    No route matches [GET] "/likes/1/create"

  8. 込み入った話になりますが、 Rails 7 で新規に作ったプロジェクトでは rails-ujs というライブラリが入らないため、 link_to 'いいねを外す', destroy_like_path(post), method: :POSTmethod: :POST が効かなくなります。そのためリクエストが POST ではなく GET で送られるようになり、ルーティングに一致しないエラーが出ます。参考ページは Rails 6 と思われるため動いているようです。

    ターミナルで ./bin/importmap pin rails-ujs を実行して rails-ujs を入れれば直ると思います。

  9. 確認ですが、エラーが出るのは likes/_like.html.erb で表示される「いいね」リンクをクリックしたときですよね?

  10. @NetaNeta0620

    Questioner

    posts/indexページのみ

              <div id="likes_buttons_<%= post.id %>">
                <%= render partial: 'likes/like', locals: {post: post} %>
              </div>
    

    上記のコードを使っています。
    indexページのいいねリンクをクリックしているため
    likes/_like.html.erb
    で表示されているいいねリンクのはずです

Your answer might help someone💌