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

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

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

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

JavaScript

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

Q&A

1回答

700閲覧

Ruby on RailsでJavaScriptの非同期通信を特定のビューファイルに適用させたいです

ryuya1204

総合スコア12

Ruby on Rails

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

JavaScript

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

0グッド

0クリップ

投稿2020/09/30 08:02

編集2020/09/30 10:00

前提・実現したいこと

Ruby on RailsでJavaScriptを非同期で実装し他ので特定のビューファイルで反映をさせたい。
現在は、ビューファイルを開いて1回目だと非同期通信が起こらない → ブラウザをリロードすると非同期通信が正常に働き、解決する。

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

JavaScriptで非同期のコードを書いた後に、デベロッパーツールのConsoleで入力を確認。 すると、 Uncaught TypeError: Cannot read property 'addEventListener' of null at price (price.js:5) というエラーが発生。一度、ブラウザをリロードすると、エラーが消え、JavaScriptの非同期通信が利用できる。 しかし、毎回リロードしないと非同期通信が起きないのでこのエラーを解決したい。

該当のソースコード

JavaScript

1 2function price() { 3 const market_price = document.getElementById("item-price"); 4 const add_tax = document.getElementById("add-tax-price"); 5 const profit = document.getElementById("profit"); 6 market_price.addEventListener("keyup", () => { 7 const selling_price = market_price.value; 8 let fee = selling_price * 0.1 9 let gains = selling_price * 0.9 10 add_tax.textContent = fee; 11 profit.textContent = gains; 12 }); 13} 14window.addEventListener("load", price);

変更したJavaScriptのコード

JavaScript

1 2function price() { 3 const market_price = document.getElementById("item-price"); 4 const add_tax = document.getElementById("add-tax-price"); 5 const profit = document.getElementById("profit"); 6 const XHR = new XMLHttpRequest(); 7 XMLHttpRequest.open("POST", `/items/${current_user_id}`, true); 8 XHR.responseType = "json"; 9 market_price.addEventListener("keyup", () => { 10 const selling_price = market_price.value; 11 let fee = selling_price * 0.1 12 let gains = selling_price * 0.9 13 add_tax.textContent = fee; 14 profit.textContent = gains; 15 }); 16} 17window.addEventListener("load", price); 18 19 20```### 該当のソースコード 21 22```html.erb 23 24<div class="items-sell-contents"> 25 <header class="items-sell-header"> 26 <%= link_to image_tag('furima-logo-color.png' , size: '185x50'), "/" %> 27 28 </header> 29 <div class="items-sell-main"> 30 <h2 class="items-sell-title">商品の情報を入力</h2> 31 <%= form_with model: @items, local: true do |f| %> 32 33 <%= render 'shared/error_messages', model: f.object %> 34 35 <%# 出品画像 %> 36 <div class="img-upload"> 37 <div class="weight-bold-text"> 38 出品画像 39 <span class="indispensable">必須</span> 40 </div> 41 <div class="click-upload"> 42 <p> 43 クリックしてファイルをアップロード 44 </p> 45 <%= f.file_field :image, id:"item-image" %> 46 </div> 47 </div> 48 <%# /出品画像 %> 49 <%# 商品名と商品説明 %> 50 <div class="new-items"> 51 <div class="weight-bold-text"> 52 商品名 53 <span class="indispensable">必須</span> 54 </div> 55 <%= f.text_area :name, class:"items-text", id:"item-name", placeholder:"商品名(必須 40文字まで)", maxlength:"40" %> 56 <div class="items-explain"> 57 <div class="weight-bold-text"> 58 商品の説明 59 <span class="indispensable">必須</span> 60 </div> 61 <%= f.text_area :discription, class:"items-text", id:"item-info", placeholder:"商品の説明(必須 1,000文字まで)(色、素材、重さ、定価、注意点など)例)2010年頃に1万円で購入したジャケットです。ライトグレーで傷はありません。あわせやすいのでおすすめです。" ,rows:"7" ,maxlength:"1000" %> 62 </div> 63 </div> 64 <%# /商品名と商品説明 %> 65 66 <%# 商品の詳細 %> 67 <div class="items-detail"> 68 <div class="weight-bold-text">商品の詳細</div> 69 <div class="form"> 70 <div class="weight-bold-text"> 71 カテゴリー 72 <span class="indispensable">必須</span> 73 </div> 74 <%= f.collection_select(:category_id, Category.all, :id, :name, {}, {class:"select-box", id:"item-category"}) %> 75 <div class="weight-bold-text"> 76 商品の状態 77 <span class="indispensable">必須</span> 78 </div> 79 <%= f.collection_select(:condition_id, Condition.all, :id, :name, {}, {class:"select-box", id:"item-sales-status"}) %> 80 </div> 81 </div> 82 <%# /商品の詳細 %> 83 84 <%# 配送について %> 85 <div class="items-detail"> 86 <div class="weight-bold-text question-text"> 87 <span>配送について</span> 88 <a class="question" href="#">?</a> 89 </div> 90 <div class="form"> 91 <div class="weight-bold-text"> 92 配送料の負担 93 <span class="indispensable">必須</span> 94 </div> 95 <%= f.collection_select(:delivery_fee_id, DeliveryFee.all, :id, :name, {}, {class:"select-box", id:"item-shipping-fee-status"}) %> 96 <div class="weight-bold-text"> 97 発送元の地域 98 <span class="indispensable">必須</span> 99 </div> 100 <%= f.collection_select(:area_id, Area.all, :id, :name, {}, {class:"select-box", id:"item-prefecture"}) %> 101 <div class="weight-bold-text"> 102 発送までの日数 103 <span class="indispensable">必須</span> 104 </div> 105 <%= f.collection_select(:ship_days_id, ShipDay.all, :id, :name, {}, {class:"select-box", id:"item-scheduled-delivery"}) %> 106 </div> 107 </div> 108 <%# /配送について %> 109 110 <%# 販売価格 %> 111 <div class="sell-price"> 112 <div class="weight-bold-text question-text"> 113 <span>販売価格<br>(¥3009,999,999)</span> 114 <a class="question" href="#">?</a> 115 </div> 116 <div> 117 <div class="price-content"> 118 <div class="price-text"> 119 <span>価格</span> 120 <span class="indispensable">必須</span> 121 </div> 122 <span class="sell-yen">¥</span> 123 <%= f.text_field :price, class:"price-input", id:"item-price", placeholder:"例)300" %> 124 </div> 125 <div class="price-content"> 126 <span>販売手数料 (10%)</span> 127 <span> 128 <span id='add-tax-price'></span>129 </span> 130 </div> 131 <div class="price-content"> 132 <span>販売利益</span> 133 <span> 134 <span id='profit'></span>135 </div> 136 </span> 137 </div> 138 </div> 139 <%# /販売価格 %> 140 141 <%# 注意書き %> 142 <div class="caution"> 143 <p class="sentence"> 144 <a href="#">禁止されている出品、</a> 145 <a href="#">行為</a> 146 を必ずご確認ください。 147 </p> 148 <p class="sentence"> 149 またブランド品でシリアルナンバー等がある場合はご記載ください。 150 <a href="#">偽ブランドの販売</a> 151 は犯罪であり処罰される可能性があります。 152 </p> 153 <p class="sentence"> 154 また、出品をもちまして 155 <a href="#">加盟店規約</a> 156 に同意したことになります。 157 </p> 158 </div> 159 <%# /注意書き %> 160 <%# 下部ボタン %> 161 <div class="sell-btn-contents"> 162 <%= f.submit "出品する" ,class:"sell-btn" %> 163 <%=link_to 'もどる', root_path, class:"back-btn" %> 164 </div> 165 <%# /下部ボタン %> 166 </div> 167 <% end %> 168 169 <footer class="items-sell-footer"> 170 <ul class="menu"> 171 <li><a href="#">プライバシーポリシー</a></li> 172 <li><a href="#">フリマ利用規約</a></li> 173 <li><a href="#">特定商取引に関する表記</a></li> 174 </ul> 175 <%= link_to image_tag('furima-logo-color.png' , size: '185x50'), "/" %> 176 <p class="inc"> 177 ©︎Furima,Inc. 178 </p> 179 </footer> 180</div> 181 182 183 184 185

試したこと

JavaScriptのコードというより、読み込みがうまくいってないため、起こっているのでは?
ruby on railsでjsファイルを読み込めるように設定をしてくれているが、特定のページに設定が出来ていないために、前のブラウザの情報が残っていることによって1回で読み込めていないのでは?
ディレクトリを確認すると、app/javascript/packs/price.js(今回適用するファイル)となっていた。

表示させたいrubyのnew.html.erbに
<%= javascript_include_tag "price.js" %>を記述すると、

Sprockets::Rails::Helper::AssetNotFound in Items#new
The asset "price.js" is not present in the asset pipeline.

というエラーが表示された。
assetファイル内にJavaScriptが無いことによるエラーだと思うが、特定のファイルを読み込ませる方法はこの場合どうすれば良いのかが分からない。
パスを指定するも、同様のエラーが出現してしまった。

説明足らずな部分があるかと思いますが、どうぞご回答よろしくお願いいたします。

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

ruby on rails 6.0.0を使用中になります。

大変お手数おかけしますがご確認よろしくお願いいたします。

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

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

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

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

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

m.ts10806

2020/09/30 08:09

id=item-price の要素はどこにあるのでしょう。 HTMLもご提示ください。
ryuya1204

2020/09/30 08:19

m.ts10806様 ご回答いただき大変ありがとうございます。 html.erbファイルを追加しました。100行目に記載をしております。 お手数おかけしますがご確認よろしくお願いいたします。
m.ts10806

2020/09/30 08:34

loadをDOMContentLoaded に変更するとどうでしょうか。
ryuya1204

2020/09/30 09:08

ご回答ありがとうございます。 load部分をDOMContentLoadedに変更して実行しましたが、同じ現象で、1回目は非同期通信が出来ておらず、リロードすると動作ができる状態になります。 実際の画面の動きをキャプチャしてみました。 https://gyazo.com/68a5916e08968fa1eb430b7e4b75d9e9 ご確認よろしくお願いいたします。
m.ts10806

2020/09/30 09:36

なるほど。確認しました。 そういえば、非同期処理をしているところはどこでしょう? キャッシュの可能性が考えられなくもないですが、「必ず1回目は動作しない」のであれば、 どこかにポイントがあるとは思うのですけど、現状提示されたコードの中からは見受けられませんでした。 複合的な要因がないとも言えないので、非同期投げているところも含めてRuby側のコードもご提示いただいたほうが良いかと思います。
m.ts10806

2020/09/30 10:01

えぇと、「current_user_id」はどこから来てるどういう情報ですか?
ryuya1204

2020/09/30 10:01

非同期処理を勘違いしており、非同期処理を行えていなかったです。 そのため、price.jsの記述に追加を行ったのですが、今度は Uncaught ReferenceErrorとなりました。 自分自身いまだによくわかっていないのですが、 XMLHttpRequestで定義されているopenメソッドの第2引数で指定しているパスの記述がよくわかっていないです。 商品を出品している本人と紐づけるために、商品の出品はログインしているユーザーしか投稿出来ない設定にしているのでcurrent_user_idと指定したのですが、定義がされていないと記述が出てしまいました。 一度質問の方も編集させていただきましたので、ご確認いただければ幸いでございます。
m.ts10806

2020/09/30 10:02

そういえば今でも再現しますか? もしかしたら更新したけど保存してないorコンパイルされてない→リロードでコンパイルされて通った のではという推測は1つしてるのですが。
m.ts10806

2020/09/30 10:03

あぁやはりそれですね。 第2引数はリクエストを送るURLなので、サーバーサイドでルーティングされているURLを指定する必要があります。current_user_idをどのように取得しているか次第で解決可能には思います。
ryuya1204

2020/09/30 10:20

丁寧にご返信いただきありがとうございます。 今はリロードをしても動作がしない状態になっております。 ルーティングは以下のように全てresourcesで作成しております。deviseを用いており、current_user_idをどのように取得しているのか自身も分からない状態となっております。正直この場合、rails routesのどの部分をみたら良いかも理解できていない状態です。 今回は、createアクションで出品を行うので、items#create の HTTPメソッドがPOST, URIが/itemsと表示されていたので、そちらを入力したところ、 Uncaught TypeError: XMLHttpRequest.open is not a function at price と表示されたので、第2引数のURLが指定できていないからかと思い、current_user_idを付け足した状態になります。 拙い文章とわかりづらい表現で大変申し訳ございません。
m.ts10806

2020/09/30 11:11 編集

質問に追記願います。 結局のところcurrent_user_idは提示されている情報内では変数としてどこで定義されることもなくいきなり現れて使われているので、「どこから来た情報なのか(どこでどのように定義された情報なのか)」を追記していただきたいのですけど。。
ryuya1204

2020/09/30 14:01

返信遅くなってしまい申し訳ございません。 そもそもなのですが、current_user_idを定義していない状態でした。 deviseのメソッドで、定義されているものかと思い、current_user_idを検索したのですが、見つからなかったです…
guest

回答1

0

ビューファイルを開いて1回目だと非同期通信が起こらない → ブラウザをリロードすると非同期通信が正常に働き、解決する。

Turbolinks特有の挙動のような気がします。
もしそうなら、下記で期待通り動くかと思いますが、いかがでしょうか?

JavaScript

1$(document).on('turbolinks:load', function() { 2 function price() { 3 const market_price = document.getElementById("item-price"); 4 const add_tax = document.getElementById("add-tax-price"); 5 const profit = document.getElementById("profit"); 6 market_price.addEventListener("keyup", () => { 7 const selling_price = market_price.value; 8 let fee = selling_price * 0.1 9 let gains = selling_price * 0.9 10 add_tax.textContent = fee; 11 profit.textContent = gains; 12 }); 13 } 14});

投稿2020/09/30 11:32

no1knows

総合スコア3365

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

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

ryuya1204

2020/09/30 14:02

ご回答いただきありがとうございます。 こちらのコードで実行をしたのですが、同様の現象は直らない状態となってしまいました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問