はじめに
プログラミング初学者の者です。オンラインでプログラミングを学習させて頂いてるのですが、さらに理解を深めていきたいと思い、学習したことを備忘録として、残して理解を深めていきたいと思います。
また、間違った点など、ありましたら、ご指摘いただけると幸いです。よろしくお願いします。
前提
Railsにて投稿アプリケーションを作成のち、投稿に対して、コメントできる機能実装済み。
今回は離乳食を投稿するアプリケーションで実装しています。
目標
コメント機能が非同期で行えるようにする
手順
①jQueryの導入
②コメント表示部分を部分テンプレート化
③投稿機能の非同期化
④削除機能の非同期化
①jQueryの導入
---------略---------
gem 'mini_magick'
gem 'image_processing', '~> 1.2'
gem 'pry-rails'
gem 'devise'
gem 'ransack'
gem 'active_hash'
gem 'jquery-rails' //追記する
次にアプリケーションのターミナルで下記コマンドを実行します。
% yarn add jquery
jQueryが追加されているか⌘+F
の検索ボックスを用いて確認します。「jQuery」と入力すると記述されていつファイルが見つかるので
・package.json => "jquery": "^*.*.*"
・yarn.lock => jquery@^*.*.*:
上記、二つにファイルが見つかれば確認完了です。
次にenvironment.js
にコードを追加します。
const { environment } = require('@rails/webpacker')
// 追加ここから
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
// 追加ここまで
module.exports = environment
application.jsにコードを追記
require("@rails/ujs").start()
// require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("jquery") //このコードを追記
require("../recipe");
ここまでで、jQueryの導入は完了です。
②コメント表示部分を部分テンプレート化
<div class="recipe-comments">
----------ここから下----------
<% @comments.each do |comment| %>
<div class="comments_list">
<div class="comments-title">
<%= comment.user.user_name %>さんの投稿
</div>
<div class="comments-items">
<div class="content">
<%= comment.content %>
</div>
<div class="comment-delete">
<% if current_user == comment.user %>
<%=link_to "削除", recipe_comment_path(comment.recipe,comment), method: :delete, class:"comment-delete" %>
<% end %>
</div>
</div>
</div>
<% end %>
----------ここまでを切り取る----------
<div id="comments"><%= render 'comments/comments', comment: @comment %></div> ///このコードを追記
<%= form_with model: [@recipe, @comment], local: true do |f| %>
<div class = 'form-group'>
<%= f.text_area :content, class: "form-control", id:"comment_content", placeholder: "コメントを記入してください" %>
</div>
<%= f.submit "コメントする", class: "btn btn-primary" , id: "submit" %>
<% end %>
</div>
</div>
<%= render "shared/footer" %>
views/commentsディレクトリの配下に_comments.html.erb
を作成して先ほどの切り取りを貼り付ける
<% @comments.each do |comment| %>
<div class="comments_list">
<div class="comments-title">
<%= comment.user.user_name %>さんの投稿
</div>
<div class="comments-items">
<div class="content">
<%= comment.content %>
</div>
<div class="comment-delete">
<% if current_user == comment.user %>
<%=link_to "削除", recipe_comment_path(comment.recipe,comment), method: :delete, class:"comment-delete" %>
<% end %>
</div>
</div>
</div>
<% end %>
③投稿機能の非同期化
form_with
のlocal: true
を外しcreate.js.erb
を探しにいくようにする。
<div class="recipe-comments">
<div id="comments"><%= render 'comments/comments', comment: @comment %></div>
<%= form_with model: [@recipe, @comment] do |f| %> ///local: trueを外す
<div class = 'form-group'>
<%= f.text_area :content, class: "form-control", id:"comment_content", placeholder: "コメントを記入してください" %>
</div>
<%= f.submit "コメントする", class: "btn btn-primary" , id: "submit" %>
<% end %>
</div>
</div>
<%= render "shared/footer" %>
コントローラーのredirect_to
を削除する
class CommentsController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy]
def create
@recipe = Recipe.find(params[:recipe_id])
@comments = @recipe.comments.includes(:user)
@comment = Comment.new(comment_params)
@comment.user_id = current_user.id
@comment.recipe_id = @recipe.id
-----ここから削除-----
if @comment.save
redirect_to recipe_path(@recipe)
end
-----ここから削除-----
@comment.save
end
def destroy
@recipe = Recipe.find(params[:recipe_id])
@recipe_comments = @recipe.comments
if Comment.find_by(id: params[:id], recipe_id: params[:recipe_id]).destroy
redirect_to recipe_path(@recipe)
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
views/comments
の配下にcreate.js.erb
を作成
$("#comment_content").val("");
$('#comments').html("<%= escape_javascript(render 'comments', comment: @comment) %>")
ここまでで、コメント投稿機能が非同期通信で行えるようになりました。
④削除機能の非同期化
link_to
ではremote: true
と指定することでdestroy.js.erb
を探しにいくようにします。
<% @comments.each do |comment| %>
<div class="comments_list">
<div class="comments-title">
<%= comment.user.user_name %>さんの投稿
</div>
<div class="comments-items">
<div class="content">
<%= comment.content %>
</div>
<div class="comment-delete">
<% if current_user == comment.user %>
<%=link_to "削除", recipe_comment_path(comment.recipe,comment), method: :delete, remote: true, class:"comment-delete" %>///deleteの後にremoteを追加
<% end %>
</div>
</div>
</div>
<% end %>
destroyアクションのredirect も削除する。
class CommentsController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy]
def create
@recipe = Recipe.find(params[:recipe_id])
@comments = @recipe.comments.includes(:user)
@comment = Comment.new(comment_params)
@comment.user_id = current_user.id
@comment.recipe_id = @recipe.id
@comment.save
end
def destroy
@recipe = Recipe.find(params[:recipe_id])
@recipe_comments = @recipe.comments
-----ここから下削除-----
if Comment.find_by(id: params[:id], recipe_id: params[:recipe_id]).destroy
redirect_to recipe_path(@recipe)
end
-----ここまで削除-----
-----ここから追記-----
@comments = @recipe.comments.includes(:user)
Comment.find_by(id: params[:id], recipe_id: params[:recipe_id]).destroy
-----ここまで追記-----
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
views/commnets
の配下にdestroy.js.erb
を作成します。
+$('#comments').html("<%= escape_javascript(render 'comments', comment: @comment) %>")
ここまで削除機能も非同期で行えるようになります。
中々、自分だけでは解決できず、Qiitaの記事を参考にさせていただきながら、質問もさせていただきながら実装することができました。もっと理解を深めるため、より詳しく説明できるようしていきたいと思います。