以前、非同期いいねで大量に困った経験があるので、Railsの非同期いいね(Railsだったら他の非同期にも使えるかも?)なエラー解決集をメモ代わりに作っておきます!
エラー解決のタイミング
(若干エラー吐かない内容もありますが、非同期のアクシデント解決の関係で入れてます)
1. RailsにjQeuryを導入する時
Qiitaでよく調べている方はご存知かもしれませんが、Railsの記事はRails6以前のものが多く、役に立たないことがあります。そこで、Rails6でのjQuery導入方法をお伝えします!
導入の手順
- Gemfileにjquery-railsを追加する
# 最終行に追加しましょう!
gem 'jquery-rails'
2.bundle install
3.javascript/packs/application.js
にimport "jquery"
を追記
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
import "jquery" // ←ここに挿入です!
import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"
Rails.start()
Turbolinks.start()
ActiveStorage.start()
これでRails6でjQueryを使えるようになりました🎉
(*CDNで代用することもできます)
たまに出てくるエラー:webpackMissingModule
webpackMissingModule
の内容が入ったエラーが
検証ツールのconsoleに出力されていることがあります。
そんな時は以下のコマンドを実行しましょう!
yarn add jquery
(railsがbundle installでnode_modulesを取ってくるのですが
なぜか取得できていない時に起こるエラーです)
2. 部分テンプレート作成時
よくある非同期いいねでは、以下のような構成です。
- likes/
- _like.html.erb
- create.js.erb
- destroy.js.erb
また、ソースコードは以下のように仮定します。
<%# 省略 %>
<% @posts.each do |post| %>
<div class="card col-md-4" style="width: 18rem;">
<%= image_tag post.image_url, class: "card-img-top" if post.image? %>
<div class="card-body">
<div class="card-text">
<%= post.body %>
</div>
<div id="likes_buttons_<%= post.id %>">
<%= render partial: 'likes/like', locals: {post: post} %>
</div>
<%= link_to '投稿詳細', post_path(post.id), class: "card-li" %>
<% if current_user.id == post.user_id %>
<%= link_to '編集', edit_post_path(post.id), class: "card-li" %>
<%= link_to '削除', post_path(post.id), method: :delete, class: "card-li" %>
<% end %><br />
<%= post.created_at.to_s(:datetime_jp) %>
</div>
</div>
<% end %>
<% if user_signed_in? %>
<% if current_user.already_liked?(post) %>
<%= link_to post_like_path(id: post.id, post_id: post.id), method: :delete, remote: true do %>
<i class="fas fa-heart"></i><%= post.likes.count %>
<% end %>
<% else %>
<%= link_to post_likes_path(id: post.id, post_id: post.id), method: :post, remote: true do %>
<i class="fas fa-heart"></i><%= post.likes.count %>
<% end %>
<% end %>
<% else %>
<i class="fas fa-heart"></i><%= post.likes.count %>
<% end %>
$('#likes_buttons_<%= post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: post}) %>");
$('#likes_buttons_<%= post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: post}) %>");
class LikesController < ApplicationController
def create
like = current_user.likes.create(post_id: params[:post_id]) #user_idとpost_idの二つを代入
redirect_back(fallback_location: root_path)
end
def destroy
like = Like.find_by(post_id: params[:post_id], user_id: current_user.id)
like.destroy
redirect_back(fallback_location: root_path)
end
end
エラー解決集
- ~.js.erbの
locals
と'#likes_buttons_<%= post.id %>'
のところで@
がない redirect_back
をコメントアウト(削除)していない-
likes_controller
で@post
を取得していない
上記のトラブルポイントについて、実際のエラーとともに見ていきましょう!
1. ~.js.erbのlocals
と'#likes_buttons_<%= post.id %>'
のところで@
がない
Started DELETE "/posts/3/likes/3" for 127.0.0.1 at 2022-08-16 00:32:28 +0900
Processing by LikesController#destroy as JS
Parameters: {"post_id"=>"3", "id"=>"3"}
Post Load (0.4ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
↳ app/controllers/likes_controller.rb:9:in `destroy'
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/controllers/likes_controller.rb:10:in `destroy'
Like Load (0.1ms) SELECT "likes".* FROM "likes" WHERE "likes"."post_id" = ? AND "likes"."user_id" = ? LIMIT ? [["post_id", 3], ["user_id", 1], ["LIMIT", 1]]
↳ app/controllers/likes_controller.rb:10:in `destroy'
TRANSACTION (0.0ms) begin transaction
↳ app/controllers/likes_controller.rb:11:in `destroy'
Like Destroy (0.7ms) DELETE FROM "likes" WHERE "likes"."id" = ? [["id", 17]]
↳ app/controllers/likes_controller.rb:11:in `destroy'
TRANSACTION (0.9ms) commit transaction
↳ app/controllers/likes_controller.rb:11:in `destroy'
Rendering likes/destroy.js.erb
Rendered likes/destroy.js.erb (Duration: 6.2ms | Allocations: 5010)
Completed 500 Internal Server Error in 22ms (ActiveRecord: 2.2ms | Allocations: 13515)
ActionView::Template::Error (undefined local variable or method `post' for #<ActionView::Base:0x00000000039008>
Did you mean? @post):
1: $('#likes_buttons_<%= post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: post}) %>");
app/views/likes/destroy.js.erb:1
「_like.html.erb
ではpost
で使ってるからいいんじゃないの?」と思ったかもしれませんが、ダメです😇
ちゃんと@
をつけましょうね!
正しいファイルたち↓
$('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");
$('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");
2. redirect_back
をコメントアウト(削除)していない
これは単純でエラーは出ませんが、likes_controller
でリダイレクトを削除していないと、ページ遷移しちゃうよって話です。せっかく非同期(ページ遷移なしでいいね)するので、ちゃんと消しましょう!
class LikesController < ApplicationController
def create
like = current_user.likes.create(post_id: params[:post_id]) #user_idとpost_idの二つを代入
# redirect_back(fallback_location: root_path)
end
def destroy
like = Like.find_by(post_id: params[:post_id], user_id: current_user.id)
like.destroy
# redirect_back(fallback_location: root_path)
end
end
3. likes_controller
で@post
を取得していない
コイツァ事案です。さっきと違ってちゃんとエラー吐きます😱
こんなエラーが出ます。そして、こいつのタチが悪いところは、現在表示しているブラウザ備え付きの検証ツールにあるConsoleを見ただけでは、解決策が見えてこない点です。
なぜかという理由の前に、まずは以下のRailsくんのログをご覧ください。
Started POST "/posts/3/likes?id=3" for 127.0.0.1 at 2022-08-16 00:21:26 +0900
Processing by LikesController#create as JS
Parameters: {"id"=>"3", "post_id"=>"3"}
(0.0ms) SELECT sqlite_version(*)
↳ app/controllers/likes_controller.rb:4:in `create'
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/controllers/likes_controller.rb:4:in `create'
TRANSACTION (0.0ms) begin transaction
↳ app/controllers/likes_controller.rb:4:in `create'
Post Load (0.0ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
↳ app/controllers/likes_controller.rb:4:in `create'
Like Exists? (0.1ms) SELECT 1 AS one FROM "likes" WHERE "likes"."post_id" = ? AND "likes"."user_id" = ? LIMIT ? [["post_id", 3], ["user_id", 1], ["LIMIT", 1]]
↳ app/controllers/likes_controller.rb:4:in `create'
Like Create (0.7ms) INSERT INTO "likes" ("post_id", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["post_id", 3], ["user_id", 1], ["created_at", "2022-08-15 15:21:26.609127"], ["updated_at", "2022-08-15 15:21:26.609127"]]
↳ app/controllers/likes_controller.rb:4:in `create'
TRANSACTION (1.0ms) commit transaction
↳ app/controllers/likes_controller.rb:4:in `create'
Rendering likes/create.js.erb
Rendered likes/create.js.erb (Duration: 1.1ms | Allocations: 1531)
Completed 500 Internal Server Error in 36ms (ActiveRecord: 2.8ms | Allocations: 27304)
ActionView::Template::Error (undefined method `id' for nil:NilClass):
1: $('#likes_buttons_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: {post: @post}) %>");
app/views/likes/create.js.erb:1
よくよく見ると、commit transaction
(DB上での処理は完了の意味)とあり、いいねを作るDBくんはしっかりと仕事をしてくれたようです。しかし、undefined method `id' for nil:NilClass
とあり、idをうまく処理できず、Viewに反映できていないようです😇
こんなダルそうなエラーですが、実はControllerにとある記述を行い、@post
を取得するだけで終わります。
class LikesController < ApplicationController
def create
@post = Post.find(params[:post_id]) # ←ここで@postをしっかり取得
like = current_user.likes.create(post_id: params[:post_id]) #user_idとpost_idの二つを代入
# redirect_back(fallback_location: root_path)
end
def destroy
@post = Post.find(params[:post_id]) # 削除時も同様に
like = Like.find_by(post_id: params[:post_id], user_id: current_user.id)
like.destroy
# redirect_back(fallback_location: root_path)
end
end
今回は以上になります!
Railsの非同期通信関係でエラー出たり、エラー吐かないけど明らかにうまくいっていない時はこの記事を見返してくださいね⭐️
それでは〜!
非同期いいねで使える記事↓
こちらはCDNでjQueryを使っていますが、参考になると思います!