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

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

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

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

【Rails】コメント機能を非同期通信にしたい

yyhoshino
yyhoshino

総合スコア1

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

1回答

1グッド

0クリップ

128閲覧

投稿2023/01/25 07:24

編集2023/01/30 02:24

前提

プログラミング初学者でして、質問させていただくにあたって、わかりにくい表現をしてしまってたり、情報が足りなくなってしまっている場合があるので、お気づきの際はご指摘していただけたら、幸いです。よろしくお願いします。

Ruby on Railsで投稿を行うアプリケーションを作成しました。
投稿に対して、コメント機能を実装しました。

実現したいこと

コメント機能をAjaxの方針の元、非同期通信を実現したいです。
まずは、コメントの投稿のみ実装を行なっており、コメントの削除を非同期通信を実現したいです。

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

コメントの投稿ボタンを押すと、フォームにテキストが残ったまま固まり、リロードを押すと投稿されます。
https://gyazo.com/6825628df82eb446f91dec3a9fa5aecd

該当のソースコード

html.show.html.erb

1<div class="recipe-comments"> 2 <%= render 'comments', comment: @comment %> 3 <%= form_with model: [@recipe, @comment] do |f| %> 4 <div class = 'form-group'> 5 <%= f.text_area :content, class: "form-control", id:"comment_content", placeholder: "コメントを記入してください" %> 6 </div> 7 <%= f.submit "コメントする", class: "btn btn-primary" , id: "submit" %> 8 <% end %> 9 </div>

form_withのlocal trueを外し、create.js.erbを呼び出す様にしています。

ruby.comment_controller.rb

1class CommentsController < ApplicationController 2before_action :authenticate_user!, only: [:create, :destroy] 3 def create 4 @recipe = Recipe.find(params[:recipe_id]) 5 @comment = Comment.new(comment_params) 6 @comment.user_id = current_user.id 7 @comment.recipe_id = @recipe.id 8 @comment.save 9 end 10 11 def destroy 12 @recipe = Recipe.find(params[:recipe_id]) 13 @recipe_comments = @recipe.comments 14 if Comment.find_by(id: params[:id], recipe_id: params[:recipe_id]).destroy 15 redirect_to recipe_path(@recipe) 16 end 17 end 18 19 private 20 def comment_params 21 params.require(:comment).permit(:content) 22 end 23end 24

redirectはさせず、jsファイルを探しにいくようにしています。

ruby.create.js.erb

1$("text_area").val(""); 2$("input").val(""); 3$('.recipe-comments').html("<%= escape_javascript(render 'comments', comment: @comment) %>")

recipes_controllerの追記

ruby.recipes_controller

1class RecipesController < ApplicationController 2 before_action :authenticate_user!, except: [:index, :show] 3 before_action :set_recipe, only: [:show, :destroy, :edit, :update,] 4 before_action :contributor_confirmation, only: [:edit, :update, :destroy] 5 def index 6 @recipes = Recipe.order(id: 'DESC') 7 end 8 9 def new 10 @recipe = Recipe.new 11 end 12 13 def show 14 @comment = Comment.new #新規コメント用 15 @comments = @recipe.comments.includes(:user) #コメント表示用投稿に関連づくコメントの取得 16 end 17 18 def edit 19 end 20 21 def update 22 if @recipe.update(recipe_params) 23 return redirect_to recipe_path(@recipe) 24 else 25 render 'edit' 26 end 27 end 28 29 def destroy 30 @recipe.destroy 31 redirect_to root_path 32 end 33 34 def create 35 @recipe = Recipe.create(recipe_params) 36 if @recipe.save 37 redirect_to root_path 38 else 39 render 'new' 40 end 41 end 42 43 def search 44 @q = Recipe.ransack(params[:q]) 45 @recipes = @q.result 46 end 47 48 private 49 def recipe_params 50 params.require(:recipe).permit( 51 :dish_name, 52 :ingredient, 53 :make, 54 :introduction, 55 :image, 56 :moon_age_id, 57 :classification_id) 58 .merge(user_id: current_user.id 59 ) 60 end 61 62 def set_recipe 63 @recipe = Recipe.find(params[:id]) 64 end 65 66 def contributor_confirmation 67 redirect_to root_path unless current_user == @recipe.user 68 end 69end

試したこと

create.js.erbファイルの記述に自信がなく、1〜2業目でテキストエリアを空にして、3行目でshow.html.erbの”recipe-commentsクラス”を呼び出し、投稿したコメントを呼び出しているので、動作すると思ったのですがうまくいきませんでした。

補足情報(FW/ツールのバージョンなど)

ruby 2.6.5
Ruby on Rails 6.0.0

わかりにく質問になってしまっているかもしれませんが、よろしくお願いいたします。
情報が足りないなどございましたら、コメントいただけると幸いです。

shinoharat👍を押しています

以下のような質問にはグッドを送りましょう

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

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

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

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

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

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

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

適切な質問に修正を依頼しましょう。

回答1

2

ベストアンサー

存在しない要素の val を呼び出そうとしてエラーになってるんだと思います。誤字を修正してみてください。

textarea
text_area

diff

1- $("text_area").val(""); 2+ $("textarea").val(""); 3 $("input").val(""); 4 $('.recipe-comments').html("......");

また、3行目で .recipe-comments の中身を書き換えていますが、これだと textarea や submit も巻き込まれ、画面から消えてしまいます。
以下のように、ピンポイントでコメント部分のみ書き換えるようにした方が良いかなと思いました。

diff

1 <div class="recipe-comments"> 2- <%= render 'comments', comment: @comment %> 3+ <div id="comments"><%= render 'comments', comment: @comment %></div> 4 <%= form_with model: [@recipe, @comment] do |f| %> 5 <div class = 'form-group'> 6 <%= f.text_area :content, class: "form-control", id:"comment_content", placeholder: "コメントを記入してください" %> 7 </div> 8 <%= f.submit "コメントする", class: "btn btn-primary" , id: "submit" %> 9 <% end %> 10 </div> 11 12 --------------------- 13 14 $("textarea").val(""); 15 $("input").val(""); 16- $('.recipe-comments').html("......"); 17+ $('#comments').html("......");

最後におまけです。
このままでも思った通りの動作はしてくれると思うのですが、 $("textarea") という指定だと「画面内の全てのテキストエリア」を意味してしまうので、ちょっと範囲が広すぎるような気がします。
こちらもピンポイントで「コメント用のテキストエリア」だけを指定した方が、思わぬ副作用を防止出来て良いかなと思いました。

diff

1- $("textarea").val(""); 2- $("input").val(""); 3+ $("#comment_content").val(""); 4 $('#comments').html("......");

他は問題ないと思います。

--

コメントの投稿ボタンを押すと、フォームにテキストが残ったまま固まり、

「固まる」ということは、サーバー側(ruby)かクライアント側(javascript)のどちらかでエラーが発生している可能性が高いです。

そういう場合は、

  1. rails server のコンソールに表示されているログ
  2. ブラウザの [開発者ツール(F12)] → [コンソール]

をそれぞれ確認してみてください。
エラーメッセージやエラー発生個所を見つければ、問題解決の大きなヒントになるはずです。

投稿2023/01/26 07:09

編集2023/01/26 07:17
shinoharat

総合スコア1280

winterboum, yyhoshino👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

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

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

このような回答には修正を依頼しましょう。

回答へのコメント

yyhoshino

2023/01/30 02:22 編集

ご連絡遅くなり、申し訳ございません。 丁寧な解説とご回答ありがとうございます。 コメント用のテキストエリアのみを指定して動作はするのですが、 「コメント投稿ボタンを押す→固まる→リロードすると投稿される」と言った状態になりました。 ご教示いただいたようにコンソールで状況を確認したところ、エラー分が確認できました。 https://gyazo.com/09429bea58b5095c3f2b55fc908b96bf **ActionView::Template::Error (undefined method `each' for nil:NilClass):** となっていまして、eachがnilになっている=@commentsがnil ということだと思うのですが、 **recipescontroller**では**showアクション**で@commentsには値を代入しているので、なぜこのようになっているのかが解決できません。。念の為、recipes_controllerのコードを本文に追記いたします。 リロードすると、コメントは生成されるので、JavaScript側(create.js.erb)で動作がうまくできていないのでしょうか?また、お時間ございましたら、教えていただけたら幸いです。よろしくお願いします。
shinoharat

2023/01/30 04:03

コメントありがとうございます! 確認します!
shinoharat

2023/01/30 04:14

RecipesController#show の処理は問題ないのですが、 CommentsController#create にも同様の処理が必要です。 ```  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 ``` !!!注意!!! 上記のサンプルコードには「全角スペース」が含まれていますので、コピぺする場合は「半角スペース」に変換してください。 teratail のコメント欄は半角スペースによるインデントが不可能なので、見やすくするため仕方なく全角スペースを使ってます。 !!!!!!!!
shinoharat

2023/01/30 04:38 編集

なぜ create にも @comments の設定が必要かと言うと、 「Rails がインスタンス変数を覚えているのは、ブラウザにレスポンスを返すまで」 だからです。 ------------------------------------------ ブラウザから「レシピの詳細ページ(RecipesController#show)を表示して」とリクエストされる  ↓ ↓ ↓ Rails が RecipesController#show を実行し、以下のインスタンス変数を設定する。  @comment  @comments そして、上記のインスタンス変数を使って show.html を作成し、ブラウザに返す。 (※※※この時点で Rails はすべてのインスタンス変数を忘れる※※※)  ↓ ↓ ↓ ブラウザは、Rails から受け取ったレスポンスを使い、レシピ詳細画面を表示する。  --- ブラウザのコメント欄から「コメントを追加(CommentsController#create)して」とリクエストされる  ↓ ↓ ↓ Rails が CommentsController#create を実行し、以下のインスタンス変数を設定する。  @comment 上記のインスタンス変数を使って create.js を作ろうとするが、 @comments が存在しないのでエラーになる。  ↓ ↓ ↓ ブラウザは、Rails から「ごめんエラーになったわ」とレスポンスを受け取る。 エラー時の処理が無いので、ブラウザはそれ以上なにもしない。 (ユーザーから見ると固まったように見える) ------------------------------------------
yyhoshino

2023/01/30 07:29

すぐにご返事していただき、大変助かります。 comments_controllerの方でも必要だったのですね。 しかも、かなり詳しくご説明いただきありがとうございます! とてもわかりやすく、腑に落ちました。上記のように、記述し直したら、該当のエラーは解消されました! その後、ブラウザのコンソールで「Uncaught ReferenceError: $ is not defined」 というエラーが出て、リロードしないとコメントが反映されない状態だったのですが、「jQuery」の導入が正常にできていなかったようで、導入したら、解決し、コメントが反映されました。 今回は私でもわかるようにご回答くださり、さらにプラスアルファな知識も教えていただき、ありがとうございました!ベストアンサーとさせていただきます!

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

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

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails 6

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。