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

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

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

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

Ruby on Rails 6

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

JavaScript

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

Q&A

1回答

619閲覧

javascriptで非同期通信による実装でレスポンスの表示がうまくいきません。

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby

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

Ruby on Rails 6

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

JavaScript

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

0グッド

0クリップ

投稿2022/10/11 08:27

編集2022/10/14 04:12

前提

チャットアプリを製作中でして、非同期通信でメッセージを送信できるように実装中です。

実現したいこと

ここに実現したいことを箇条書きで書いてください。

  • エラーを解決してメッセージを表示したいです。

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

送信ボタンを押した際にブラウザに反映されず、下記のようなエラーがでてしまいました。

イメージ説明

上記のエラーをクリックすると下記のようにでてきます。

イメージ説明

該当のソースコード

routes.rb

1Rails.application.routes.draw do 2 devise_for :users 3 root to: "rooms#index" 4 resources :users, only: [:show, :edit, :update] 5 resources :rooms, only: [:new, :create, :destroy] do 6 resources :messages, only: [:index, :create] 7 end 8end

messageモデル

1class Message < ApplicationRecord 2 belongs_to :room 3 belongs_to :user 4 has_one_attached :image 5 6 validates :content, presence: true, unless: :was_attached? 7 8 def was_attached? 9 self.image.attached? 10 end 11end

MessagesController

1class MessagesController < ApplicationController 2 before_action :set_room, only: [:index, :create] 3 4 def index 5 @message = Message.new 6 @messages = @room.messages.includes(:user) 7 end 8 9 def create 10 @message = @room.messages.new(message_params) 11 @user = @message.user 12 if @message.save 13 render json:{ message: @message, user: @user} 14 else 15 @messages = @room.messages.includes(:user) 16 render :index 17 end 18 end 19 20 private 21 22 def set_room 23 @room = Room.find(params[:room_id]) 24 end 25 26 def message_params 27 params.require(:message).permit(:content, :image).merge(user_id: current_user.id) 28 end 29end

message.js

1const buildHTML = (XHR) => { 2 const item = XHR.response.message; 3 const user = XHR.response.user 4 const html = ` 5 <div class="message"> 6 <div class="upper-message"> 7 <div class="message-user"> 8 ${user.name} 9 </div> 10 <div class="message-date"> 11 ${item.created_at} 12 </div> 13 </div> 14 <div class="lower-message"> 15 <div class="message-content"> 16 ${item.content} 17 </div> 18 <img src= ${item.image} width="300" height="300" class: ”message-image" if message.image.attached?> 19 </div> 20 </div>`; 21 return html; 22}; 23 24function message (){ 25 const submit = document.getElementById("submit"); 26 if (!submit){ return false;} 27 submit.addEventListener("click", (e) => { 28 e.preventDefault(); 29 const form = document.getElementById("messageform"); 30 const formData = new FormData(form); 31 const XHR = new XMLHttpRequest(); 32 const url = location.pathname 33 XHR.open("POST", url, true); 34 XHR.responseType = "json"; 35 XHR.send(formData); 36 XHR.onload = () => { 37 if (XHR.status != 200) { 38 alert(`Error ${XHR.status}: ${XHR.statusText}`); 39 return null; 40 }; 41 const list = document.getElementById("messagelist") 42 const formText = document.getElementById("content"); 43 list.insertAdjacentHTML("afterend", buildHTML(XHR)); 44 formText.value = ""; 45 }; 46 }); 47 }; 48 49 window.addEventListener('load', message);

index.html.erb

1<%= render "shared/header" %> 2 3<div class="wrapper"> 4 <div class="sidebar"> 5 <%= render "side_bar" %> 6 </div> 7 <div class="chat"> 8 <%= render "chat" %> 9 </div> 10</div>

_chat.html.erb

1〜略〜 2<div class="messages"> 3 <%= render partial: 'message', collection: @messages %> 4</div> 5 6<%= form_with model: [@room, @message], class: 'form', id: 'messageform' do |f| %> 7 <div class="form-input"> 8 <%= f.text_field :content, class: 'form-message', placeholder: 'メッセージを入力', id: "content" %> 9 <label class="form-image"> 10 <span class="image-file">画像</span> 11 <%= f.file_field :image, class: 'hidden' %> 12 </label> 13 </div> 14 <%= f.submit '送信', class: 'form-submit', id: "submit" %> 15<% end %>

_message.html.erb

1<div class="message", id="messagelist" > 2</div>

試したこと

エラー分で検索してもいまいちヒットしません。

console.log(item)を実行し、確認しました。レスポンスが返ってきているとは思うのでconst htmlの所の書き方がいけないんでしょうか...
イメージ説明

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

イメージ説明
イメージ説明

以下、404エラーのターミナルです。
イメージ説明

以下、@messagesの出力結果です。
イメージ説明

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

console.log(item)の内容を見るに、itemの中にuser_idはありますが、userは存在しないのではないでしょうか?
以下のように、user部分を省けばエラーは発生しないようになるかと思います。

diff

1const html = ` 2 <div class="message"> 3 <div class="upper-message"> 4 <div class="message-user"> 5- ${item.user.name} 6 </div> 7 <div class="message-date"> 8 l ${item.created_at} 9 </div> 10 </div> 11 <div class="lower-message"> 12 <div class="message-content"> 13 ${item.content} 14 </div> 15 <img src=${item.image}, class: ”message-image"> 16 </div> 17 </div>`;

投稿2022/10/11 09:30

hayato7

総合スコア1135

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/10/15 13:51 編集

回答ありがとうございます。 指摘していただいたように${item.name}としたところ、今度は下記のエラーがでました。 GET http://localhost:3000/rooms/10/undefined, 404 (Not Found) ここのitem.user.nameというのはuserテーブルのnameを表示する記述ですが、やはりここがあやしいでしょうか?
hayato7

2022/10/11 10:15

${item.user.name}を${item.name}に書き換えるということではなく、この部分の記述を完全に削除したら動くのでは?という内容でした。 message.js内のitemというのは、HTTPレスポンスに含まれるmessageを取得しています。 const item = XHR.response.message; そしてその中身はというと、MessagesControllerのcreateメソッドの以下の部分だと思います。 jsonを返す時にuserが含まれていませんので、js側からはuserを取得できません。 if @message.save render json:{ message: @message}
退会済みユーザー

退会済みユーザー

2022/10/11 11:42 編集

${item.user.name}を消すということでしたか。申し訳ないです。 指摘の通りにしましたら、送信されました。 render json:{ message: @message}という記述からuserが取得できていないということで、挑戦していますが、苦戦中です。userテーブルのnameを取得したいため、下記のようにしてみたりしていますがエラーがでて、解決しません。恐縮ですが、助言頂けないでしょうか。 ```messages_controller 〜省略〜 def create @message = @room.messages.new(message_params) + @user = User.find(params[:user_id]) if @message.save + render json:{ message: @message, user: @user} else 〜省略〜 ``` ```message.js 〜省略〜 XHR.onload = () => { const list = document.getElementById("messagelist") const formText = document.getElementById("content"); const item = XHR.response.message; + const user = XHR.response.user const html = ` <div class="message"> <div class="upper-message"> <div class="message-user"> + ${user.name} </div> 〜省略〜 ``` +部が追記したものです。
退会済みユーザー

退会済みユーザー

2022/10/11 13:30

itemにuser_idが格納されているのでconst user = XHR.response.userの記述は必要無い気がしてきました。 itemにあるuser_idをどう返すかですよね。悩ましいです。引き続き、粘っていますので空いてる時間にでもお助けいただけると幸いです。
hayato7

2022/10/12 02:41

> userテーブルのnameを取得したいため、下記のようにしてみたりしていますがエラーがでて、解決しません。恐縮ですが、助言頂けないでしょうか。 こちらのエラーはどういった内容のものでしょうか?
退会済みユーザー

退会済みユーザー

2022/10/12 02:50

返信ありがとうございます。 上記のコードを記述し、でたエラーの画像を補足情報にアップロードしました。 よろしくお願いいたします。
hayato7

2022/10/12 03:03

ありがとうございます。 サーバーサイド(rails)の方でエラーが発生し、404が返ってきているように思います。 railsの方でログファイルを確認すると、エラー内容が見られるかと思います。 おそらくuser_idの部分に問題があると思うので、以下のような形にすればuserを取得できるようになるのではないかと思います。 @message = @room.messages.new(message_params) + @user = @message.user // または、 @user = User.find(current_user.id)
退会済みユーザー

退会済みユーザー

2022/10/12 06:26

@user = @message.userに修正することでuserのnameを表示することができました。 修正後、404エラーをターミナルにて確認すると下記のように表示されています。 ```ターミナル Started GET "/rooms/10/undefined" for ::1 at 2022-10-12 15:01:15 +0900 ActionController::RoutingError (No route matches [GET] "/rooms/10/undefined"): ``` "/rooms/10/undefinedがありませんといった意味でしょうか。 なぜundefinedになっているのかわかりません。 エラー分からコントローラー、ルーティングを確認していますが異常は無い気がします。
hayato7

2022/10/12 07:47 編集

> 修正後、404エラーをターミナルにて確認すると下記のように表示されています。 404エラーは、どのタイミングで発生しているのでしょうか? Started GET "/rooms/10/undefined" (...略) 上記の内容から、GETメソッドが利用されていることがわかるので、フォームの送信とは、関係ないように思えます。
退会済みユーザー

退会済みユーザー

2022/10/12 08:00

送信後にエラーがでています。 質問フォーマットのソースコードの方、現在のものに更新し、補足の方にターミナルの画像を載せました。 度々申し訳ありませんが、よろしくお願いいたします。
退会済みユーザー

退会済みユーザー

2022/10/12 08:12 編集

これもしかしてjavascriptの方でimageが返されていないとかっていう原因ありますかね? 試しに画像を送信してみても表示されなかったので。
hayato7

2022/10/12 08:12

ありがとうございます。 状況おそらく理解できました。 ryosukeさんの仰るとおり、imageがないですね。 なので、下記を削除するとエラーが発生しないのではないでしょうか? ``` <img src=${item.image}, class: ”message-image"> ``` ${item.image}がundefinedになるので、結果的に、/rooms/10/undefinedというURLをリクエストしてしまっています。
退会済みユーザー

退会済みユーザー

2022/10/12 08:17

おっしゃる通り、削除しましたら、エラー消えました。 ありがとうございます。 アクティブストレージを使って画像を保存していますが、javascriptに別の記述が必要ってことですね?
hayato7

2022/10/12 08:51

正しい画像URLを取得する必要がありますね。 アクティブストレージに保存している画像のURLは、どのように管理されているのでしょうか? 例えば、1メッセージに添付できる画像が1つだけなのであれば、messageテーブルにimg_urlカラムを用意し、そこでURLを持たせていたりします。
退会済みユーザー

退会済みユーザー

2022/10/12 09:02

1メッセージにつき、画像一つですが、messagesテーブルにimageに関するカラムは現状ありません。 active_storage_blobsテーブルとactive_storage_attachmentsテーブルが存在し、javascriptによるajax通信に取り組む前は表示できていたんですが、javascriptに反映させるためにはimg_urlといったカラムを用意する必要があるんですね?
hayato7

2022/10/12 09:04

管理の例としてあげただけですので、カラムを用意する必要はありません。 > javascriptによるajax通信に取り組む前は表示できていた このときは、どのようなコードで表示されていましたか?
退会済みユーザー

退会済みユーザー

2022/10/12 09:04

messageモデルにhas_one_attached :imageで紐づけています。
hayato7

2022/10/12 09:05

であれば、 バックエンド側で、message.imageで取得できるということですよね。 userの場合と同じく、それでフロント側にimageのurlも渡すことができるのではないでしょうか?
退会済みユーザー

退会済みユーザー

2022/10/12 09:39

たしかにmessage.imageにて取得できていました。 すみません。挑戦中ですが書き方がわかなくて... render json:{ message: @message, user: @user}ここにimageも返すように追記すればいいということですよね? 下記のようにしてみましたが ```messages_controller @image = message.image render json:{ message: @message, user: @user, image: @image} ``` ```message.js const image = XHR.response.image <img src= ${image} > ``` こちらの記述は正しくなく、下記のエラーがでてしまいます。 POST http://localhost:3000/rooms/10/messages 500 (Internal Server Error)
hayato7

2022/10/12 10:15

> render json:{ message: @message, user: @user}ここにimageも返すように追記すればいいということですよね? そうです。 フォーム送信時に500エラー(サーバー側でエラーが発生)になっているので、 @image = message.imageを追加してエラーが発生した可能性が高いと考えられます。
hayato7

2022/10/12 10:37

調べてみたところ、blobのまま送信しようとしてエラーが発生している可能性があります。 アクティブストレージをAPIで利用する場合、通常の方法ではだめなようです。 以下の記事なんかが参考になるかと思います。 https://sato-s.github.io/2018/08/25/active-storage-in-API.html
hayato7

2022/10/12 11:35

> ダイレクトアップロードという機能がActive Storageに備わっているみたいですがこちらはどうでしょう? ダイレクトアップロードというのは、Railsサーバーを通さずに例えば、Amazon S3などのクラウドサービスに直接アップロードする機能です。そのため、今は関係ないですね。
退会済みユーザー

退会済みユーザー

2022/10/12 11:41

hayatoさんが送ってくれたURLのイメージのアップロードのところですが、『普通のフォームを使うことで』というのは私で言うとform_withのことになるんですかね。 その下の『レスポンスにイメージ格納先のURLを追加する。』というところが解決への糸口になりそうですね。
退会済みユーザー

退会済みユーザー

2022/10/12 11:41

ダイレクトアップロードの件、なるほどです。
退会済みユーザー

退会済みユーザー

2022/10/12 12:49

https://sato-s.github.io/2018/08/25/active-storage-in-API.html 上記のURLのレスポンスにイメージ格納先のURLを追加するを実際にやってみましたが実際に返ってきているのか確認の仕方がわかりません。 ```app/models/message.rb include Rails.application.routes.url_helpers def image_url image.attached? ? url_for(image) : nil end ``` ```config/environments/development.rb Rails.application.routes.default_url_options[:host] = 'localhost' Rails.application.routes.default_url_options[:port] = 3000 ``` ```app/controllers/messages_controller.rb render json:{ message: @message, user: @user, methods: [:image_url]} ```
hayato7

2022/10/12 21:18

この時フォーム送信を行うとどうなりますか?
hayato7

2022/10/12 21:32 編集

確認の仕方についてですが、apipry-railsを利用してデバッグする方法があります。
退会済みユーザー

退会済みユーザー

2022/10/13 01:11 編集

上記まではできたのですが、javascriotの方にどう記述したらimage画像を取得できるのかわからなくて... 下記のような感じでやってみたりしましたが、 const image = XHR.response.image_url <img src= "{url_for('static', filename='image')}"> おそらく書き方があってなくて下記のエラーが表示されてしまいました。 GET http://localhost:3000/rooms/10/%7Burl_for('static',%20filename='image_url')%7D 404 (Not Found)
退会済みユーザー

退会済みユーザー

2022/10/13 01:33

const image = XHR.response.image_url <img src= "${image}"> ともやってみましたが、下記のエラーでやはりimageが取得できていないようです。 GET http://localhost:3000/rooms/10/undefined 404 (Not Found)
hayato7

2022/10/13 07:18

``` const image = XHR.response.image_url <img src= "${image}"> ``` 上記コードがundefinedになっているので、rails側でimage_urlがうまく作成できていない可能性が高いですね。 APIを利用したデバッグが難しそうなのであれば、以下のindexの方であればデバッグも行いやすいと思います。 ``` def index @message = Message.new @messages = @room.messages.includes(:user) // ここであるmessageから、画像urlがどう取得できるか end ```
退会済みユーザー

退会済みユーザー

2022/10/13 15:08

返信遅くなり、申し訳ないです。 def index @message = Message.new @messages = @room.messages.includes(:user) binding.pry end とし、 ターミナルにて下記のようにしてみました。 pry(#<MessagesController>)>  @message.image => #<ActiveStorage::Attached::One:0x00007f9eb98f48a0 @name="image", @record=#<Message:0x00007f9eb6de55b0 id: nil, content: nil, room_id: nil, user_id: nil, created_at: nil, updated_at: nil>> と出てきましたがたぶん関係ないですよね。 下記もやってみましたがnilと表示されてしまっています。 pry(#<MessagesController>)> @message.image_url => nil image_urlがやはりちゃんと作成できていないみたいですね。 挫けそうです...
hayato7

2022/10/14 02:30

``` pry(#<MessagesController>)>  @message.image ``` 上記の結果は、@message = Message.newのimageを取得しているので、データが入っていないのではないでしょうか。 できれば、@messagesから1件取り出して、もう一度ターミナルで確認してみてもらえますか? > 挫けそうです... 着実に進んでいると思いますので、もう少しの辛抱です。 githubなどでコードを共有いただければ、こちらでも環境作成して確認できますが、難しそうでしょうか?
退会済みユーザー

退会済みユーザー

2022/10/14 04:16

返信ありがとうございます。 binding.pryにて@messagesを出力してみましたがこれでよろしかったでしょうか?(補足に画像を追加しました) 現在、コミット前でして、うまくいかないようであれば保留にして別の追加実装をしようとも考えていたところでして,,,
hayato7

2022/10/15 12:46

> binding.pryにて@messagesを出力してみましたがこれでよろしかったでしょうか?(補足に画像を追加しました) messagesではなく、messagesからmessageを一件取得していただきたいです。 > 現在、コミット前でして、うまくいかないようであれば保留にして別の追加実装をしようとも考えていたところでして,,, コミット前でも環境や既存のコードがわかればいいので、問題なければ共有いただければと思います。
退会済みユーザー

退会済みユーザー

2022/10/15 13:58

返信ありがとうございます。 > messagesではなく、messagesからmessageを一件取得していただきたいです。 すみません。どうしたらいいのかわかりません... githubの共有というのはリポジトリのURLを貼れば大丈夫でしょうか?
退会済みユーザー

退会済みユーザー

2022/10/15 14:39

すみません。調べているとAction Cableという自動更新機能がrailsには備わっていて、私がやりたいことは寧ろそっちだと今更ながら思ってしまいました。 大変申し訳ないですが、そっちに切り替えようと考えています。 長々と付き合って頂いて、親切に接して頂いて、本当に感謝しています。
hayato7

2022/10/16 06:03

なるほど、リアルタイム通信でやりとりできるようにしたいのですね。 であれば確かにWebSocketを利用するのがいいと思います。 こちらの質問についてはクローズしていただければと思います。
退会済みユーザー

退会済みユーザー

2022/10/16 06:39

hayatoさん長々と付き合って頂いて、本当にありがとうございました。 本当に感謝してます。 ありがとうございました!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問