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

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

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

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

JavaScript

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

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

HTML

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

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

Q&A

2回答

1118閲覧

リーグ戦の勝敗を非同期処理で記入して保存する

Zengo_Master

総合スコア19

Ruby on Rails

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

JavaScript

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

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

HTML

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

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

0グッド

0クリップ

投稿2020/09/27 13:03

編集2020/10/14 07:16

解決したいこと

Ruby on Railsで総当たりリーグ戦を実装しています。以下は、現在のフロントです。
イメージ説明

ここに、対戦結果を非同期処理(tdをクリック)で記入して、データベースに保存できるように実装したいです。

現在できている実装

tdをクリックすると、非同期処理でそこに○が表示され、反対側に●が表示されるようになっています。

詰まっている実装

結果の記入は出来るのですが、ページをリロードすると○と●が全て消えてしまいます。そこで、データベースの中で更新(例:空白→○)するように実装したいです。

データベース設計

membersテーブル(10人)
・メンバーID
・メンバー名
・アカウント
・実績
・勝ち数
・負け数
・SB

resultsテーブル(1人に対して9人(10人))
・メンバーID
・対戦相手ID
・勝敗

現在のコード

ruby

1Rails.application.routes.draw do 2 root to: 'results#index' 3 get 'results/:id', to: 'results#win_or_lose' 4end

ruby

1class ResultsController < ApplicationController 2 3 def index 4 @members = Member.all 5 end 6 7 def win_or_lose 8 // 数字_数字を分解 9 resultAry = params[:id].split("_") 10 // 左側が勝利のtd 11 result_win = Result.find(resultAry[0]) 12 // 右側が敗北のtd 13 result_lose = Result.find(resultAry[1]) 14 15 if result_win.result == "○" 16 result_win.update(result: "") 17 result_lose.update(result: "") 18 else result_win.result == "" 19 result_win.update(result: "○") 20 result_lose.update(result: "●") 21 end 22 end 23 24end

html

1<div class="main"> 2 <div class="league-table"> 3 <h2 class="league-table-title">【リーグ表】</h2> 4 <table id="winorlose_table" border="2" bordercolor="black" style="border-collapse: collapse"> 5 <tr class="top-title"> 6 <th class="rank-title">順位</th> 7 <th class="player-title">対局者</th> 8 9 <% @members.each do |member| %> 10 <td class="opponent-name"><%= member.name %></td> 11 <% end %> 12 13 <th class="win-count-title"></th> 14 <th class="lose-count-title"></th> 15 <th class="sb-count-title">SB</th> 16 </tr> 17 18 <% @members.each_with_index do |member, i| %> 19 <tr class="result-cells"> 20 <td id="rank_<%= i + 1 %>"></td> 21 <td class="self-name"><%= member.name %></td> 22 // 勝敗記入のtd 23 <td id="op_<%= i + 1 %>_1" data-id="<%= (i * 10) + 1 %>_<%= (10 * (i * 10 + 1)) - (100 * i + (9 - i)) %>"><%= Result.find((i * 10) + 1).result %></td> 24// 途中略 25 <td id="op_<%= i + 1 %>_10" data-id="<%= (i * 10) + 10 %>_<%= (10 * (i * 10 + 10)) - (100 * i + (9 - i)) %>"><%= Result.find((i * 10) + 10).result %></td> 26 // 勝敗のtd 27 <td id="win_<%= i + 1 %>">0</td> 28 <td id="lose_<%= i + 1 %>">0</td> 29 <td id="sb_<%= i + 1 %>">0</td> 30 </tr> 31 <% end %> 32 33 </table> 34 </div> 35</div>

css

1.header { 2 margin: 20px; 3 padding-bottom: 5px; 4 border-bottom: 2px solid lightgray; 5} 6 7.header span { 8 padding-left: 20px; 9 font-size: 25px; 10} 11 12.main { 13 margin: 30px; 14} 15 16.league-table { 17 margin-top: 20px; 18} 19 20.league-table-title { 21 margin-bottom: 5px; 22} 23 24.league-table td { 25 text-align: center; 26} 27 28.right_down_border { 29 background-image: linear-gradient(to top right, transparent, transparent 48%, black 49%, black 51%, transparent 52%, transparent); 30} 31 32.top-title { 33 height: 30px; 34} 35 36.rank-title { 37 width: 50px; 38 background-color: #FFFFAA; 39} 40 41.player-title { 42 width: 80px; 43 background-color: #EEEEEE; 44} 45 46.opponent-name { 47 width: 80px; 48 background-color: #EEEEEE; 49} 50 51.win-count-title { 52 width: 50px; 53 background-color: #FFD5EC; 54} 55 56.lose-count-title { 57 width: 50px; 58 background-color: #D9E5FF; 59} 60 61.sb-count-title { 62 width: 50px; 63 background-color: #F3FFD8; 64} 65 66.result-cells { 67 height:40px ; 68} 69 70.self-name { 71 height:40px ; 72 background-color: #EEEEEE; 73} 74 75.member-list { 76 margin-top: 30px; 77} 78 79.member-list-title { 80 margin-bottom: 5px; 81} 82 83.member-table td { 84 text-align: center; 85} 86 87.member-info { 88 height: 30px; 89} 90 91.member-title { 92 width: 100px; 93 text-align: center; 94 background-color: #EEEEEE; 95} 96 97.account-title { 98 width: 150px; 99 text-align: center; 100} 101 102.achievement-title { 103 width: 500px; 104 text-align: center; 105} 106 107.member-introduction td { 108 height: 30px; 109}

js

1// ※リーグ表の中身の定義 2var json_data = {"_1":{ 3 "member":"Aさん", 4 "_1":{"member":"Aさん","WinOrLose":9}, 5// 途中略 6 "_10":{"member":"Jさん","WinOrLose":0} 7 }, 8 9// 途中略 10 11 "_10":{ 12 "member":"Jさん", 13 "_1":{"member":"Aさん","WinOrLose":0}, 14// 途中略 15 "_10":{"member":"Jさん","WinOrLose":9} 16 } 17 }; 18 19// 初期処理 20function init(){ 21 var trs = document.getElementById("winorlose_table").getElementsByTagName('tr'); 22 // 1行目はヘッダーだから飛ばして 23 for(var itr = 1; itr < trs.length; itr++){ 24 var win = 0; 25 var lose = 0; 26 // テーブルの行毎に処理 27 var tds = trs[itr].getElementsByTagName('td'); 28 for(var itd = 0; itd < tds.length; itd++){ 29 if(tds[itd].id.indexOf('op_') != -1){ // idにop_を含む(勝敗記入のtd) 30 // 勝ち負け入力<td>タグの場合 31 var arr = tds[itd].id.split('_'); // op_数字_数字 → [op, 数字, 数字] 32 if(arr[1] == arr[2]){ 33 // 対戦が同じ場合 34 tds[itd].classList.add('right_down_border'); // 縦横同値マスにクラスを指定 35 } 36 else { 37 // 勝ち数を加算 38 if(tds[itd].innerHTML == '○'){ 39 win ++; 40 } 41 // 負け数を加算 42 else if(tds[itd].innerHTML == '●'){ 43 lose ++; 44 } 45 // 対戦が違う場合、イベントを登録 46 // onclick="winorlose_click(this);" と同じ内容 47 tds[itd].addEventListener('click', {name: this, handleEvent: winorlose_click}); 48 if(json_data['_'+ arr[1]]['_'+ arr[2]]["WinOrLose"] == 1){ 49 tds[itd].innerHTML = "○"; 50 } 51 else if(json_data['_'+ arr[1]]['_'+ arr[2]]["WinOrLose"] == -1) { 52 tds[itd].innerHTML = "●"; 53 } 54 } 55 } 56 else if(tds[itd].id.indexOf('win_') != -1) { 57 // 勝ち表示 58 tds[itd].innerHTML = win; 59 } 60 else if(tds[itd].id.indexOf('lose_') != -1) { 61 // 負け表示 62 tds[itd].innerHTML = lose; 63 } 64 } 65 } 66} 67 68// クリックしたときの処理 69var send_winorlose = false; 70var XHR; 71function winorlose_click(el){ 72 if(send_winorlose) return; // 送信中は実行できない 73 send_winorlose = true; // 処理中とする 74 75 // el にはどこでクリックされたかの情報が入っている 76 var arr = el.target.id.split('_'); // idを'_'で分ける .targetで親要素イベントも発火 77 var oppid = arr[0] + '_' + arr[2] + '_'+ arr[1]; // 反対側のid 78 // 勝敗の記入と取消 79 if(el.target.innerHTML == ''){ // 勝敗を記入 80 el.target.innerHTML = '○'; // 勝ち 81 document.getElementById(oppid).innerHTML = '●'; // 負け 82 json_data['_'+ arr[1]]['_'+ arr[2]]["WinOrLose"] = 1; //jsonのデータ自体を更新 83 json_data['_'+ arr[2]]['_'+ arr[1]]["WinOrLose"] = -1; //jsonのデータ自体を更新 84 } 85 else if(el.target.innerHTML == '○'){ // 勝敗を取消 86 el.target.innerHTML = ''; // 空白 87 document.getElementById(oppid).innerHTML = ''; // 空白 88 json_data['_'+ arr[1]]['_'+ arr[2]]["WinOrLose"] = 0; //jsonのデータ自体を更新 89 json_data['_'+ arr[2]]['_'+ arr[1]]["WinOrLose"] = 0; //jsonのデータ自体を更新 90 } 91 92 // 勝ち数と負け数の計算 93 var trs = document.getElementById("winorlose_table").getElementsByTagName('tr'); 94 var win = 0; 95 var lose = 0; 96 // 1行目はヘッダーだから飛ばして 97 for(var itr = 1; itr < trs.length; itr++){ 98 // テーブルの行毎に処理 99 win = 0; 100 lose = 0; 101 var tds = trs[itr].getElementsByTagName('td'); 102 for(var itd = 0; itd < tds.length; itd++){ 103 if(tds[itd].id.indexOf('op_') != -1){ 104 // 勝ち負け数カウント 105 if(tds[itd].innerHTML == '○'){ 106 win ++; 107 } else if(tds[itd].innerHTML == '●'){ 108 lose ++; 109 } 110 } else if(tds[itd].id.indexOf('win_') != -1){ 111 // 勝ち表示 112 tds[itd].innerHTML = win; 113 } else if(tds[itd].id.indexOf('lose_') != -1){ 114 // 負け表示 115 tds[itd].innerHTML = lose; 116 } 117 } 118 } 119 120 //※ データの送信は処理の最後 121 //※ 非同期でも結果が返ってくるまでクリックを無視するように変更 122 let resultId = el.target.getAttribute("data-id"); 123 if(!XHR){ 124 XHR = new XMLHttpRequest(); 125 XHR.responseType = "json"; 126 XHR.onload = function() { 127 send_winorlose = false; // 送信完了 128 }; 129 XHR.onerror = function() { 130 send_winorlose = false; // 送信完了 131 }; 132 } 133 XHR.open("GET", `/results/${resultId}`, true); 134 XHR.send(); 135} 136 137window.addEventListener("load", init);

調べた内容

・[Rails] Ajaxを用いて非同期通信でチャットメッセージを送る
https://qiita.com/kumasuke/items/36365bcdf30eaea65250

チャットのようにメッセージを非同期で入力するには、Ajaxを使うとありましたが、クリックすると既存のtdに○を表示することに応用を利かすのが難しいです。

tdをクリックした際の処理を実装する

クリックしたtdに○が付いて、反対側のtdに●が付く。
→データベースのresult.op_1からresult.op_10までのいずれかが、空白から○に更新される。

Ajaxで以上の実装をするにあたって、参考となる記述や参考を教えていただけると助かります。よろしくお願いします。

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

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

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

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

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

kuma_kuma_

2020/09/27 13:07

せっかくサンプルかいたのにやめちゃったんだ... あれで初期値も渡せたのに...
Zengo_Master

2020/09/27 13:17 編集

いつもありがとうございます。 ビューファイルはeach_with_indexを使って短くできました。 jsファイルは解読が難しくて別の書き方をしてしまいました。またあのサンプルでやり直してみます。
kuma_kuma_

2020/09/27 13:18

あの処理でinit()って処理あったでしょ? あれは初期設定をするっていう意味。 あの時初期値の話が無かったけど、初期値があるならあそこで設定するのがセオリーだから。
yambejp

2020/09/27 13:34

サーバーに保持するのが絶対条件ですか? localhostやクッキーで保持してはいけないのでしょうか? またサーバーに保持するとしてもjsonデータで保持するとかはNGですか?
Zengo_Master

2020/09/27 13:41

>サーバーに保持するのが絶対条件ですか? はい。最終的にHerokuやAWSで動かします。 リロードしても対戦結果(○と●)を残すことが目的です。 >サーバーに保持するとしてもjsonデータで保持するとかはNGですか? jsonデータはOKです。
kuma_kuma_

2020/09/27 13:46

> jsonデータはOKです。 それなら前回回答したinit()で処理できるよ!
guest

回答2

0

【Rails入門】JSON.parseでパラメーターをHashに変換する方法
これでJSON形式の受け渡しができます。
あとは以前回答したinitのイベント設定時に受け取った
JSON形式の値"○""●"を設定すればよいだけです。

追記
JSONデータの持ち方
"WinOrLose"は
勝ち = 1
負け = -1
未設定 = 0
同一 = 9
で設定したとして

Javascript

1 var json_data = {"_1":{ 2 "member":"Aさん", 3 "_1":{"member":"Aさん","WinOrLose":9}, 4 "_2":{"member":"Bさん","WinOrLose":1}, 5 "_3":{"member":"Cさん","WinOrLose":-1} 6 }, 7 "_2":{ 8 "member":"Bさん", 9 "_1":{"member":"Aさん","WinOrLose":-1}, 10 "_2":{"member":"Bさん","WinOrLose":9}, 11 "_3":{"member":"Cさん","WinOrLose":1} 12 }, 13 "_3":{ 14 "member":"Cさん", 15 "_1":{"member":"Aさん","WinOrLose":1}, 16 "_2":{"member":"Bさん","WinOrLose":-1}, 17 "_3":{"member":"Cさん","WinOrLose":9} 18 } 19 };

という形になります。
これはDBから取得したデータそのままの構造です。

検索する際にはこの様に使います

Javascript

1console.log(json_data["_1"]["member"]); 2// 行"_1"のメンバーは? "Aさん" 3 4console.log(json_data["_1"]["_3"]["member"]); 5// 行"_1"列"_3"のメンバーは? "Cさん" 6 7console.log(json_data["_2"]["_1"]["WinOrLose"]); 8// 行"_2"列"_1"の勝敗は? -1(負け)

JSON構造が階層構造だから難しく感じるかもしれないけれど
なれるととても便利だから頑張って覚えてね!

追記2
前の回答の内容に追記しました(※部分)
(ここは学習ポイントなので自力でがんばってほしかった...)

Javascript

1 // 初期処理 2 function init(){ 3 var trs = document.getElementById("winorlose_table").getElementsByTagName('tr'); 4 // 1行目はヘッダーだから飛ばして 5 for(var itr = 1; itr < trs.length; itr++){ 6 // テーブルの行毎に処理 7 var tds = trs[itr].getElementsByTagName('td'); 8 for(var itd = 0; itd < tds.length; itd++){ 9 if(tds[itd].id.indexOf('cell_') != -1){ 10 // 勝ち負け入力<td>タグの場合 11 var arr = tds[itd].id.split('_'); 12 if(arr[1] == arr[2]){ 13 // 対戦が同じ場合 14 tds[itd].classList.add('right_up_border'); // 斜め線を指定 15 }else{ 16 // 対戦が違う場合、イベントを登録 17 // onclick="winorlose_click(this);" とおんなじ内容 18 tds[itd].addEventListener('click', {name: this, handleEvent: winorlose_click}); 19 // ※ここで設定 20 if(json_data['_'+ arr[1]]['_'+ arr[2]]["WinOrLose"] == 1){ 21 tds[itd].innerHTML = "○"; 22 } else if(json_data['_'+ arr[1]]['_'+ arr[2]]["WinOrLose"] == -1){ 23 tds[itd].innerHTML = "×"; 24 } 25 } 26 } 27 } 28 } 29 }

投稿2020/09/27 23:20

編集2020/09/29 09:35
kuma_kuma_

総合スコア2506

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

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

Zengo_Master

2020/09/28 17:23 編集

ありがとうございます。 function initの中に以下を書く感じですか? json_white = '{"rails": {"json": "○"}}' win = JSON.parse(json_white) json_black = '{"rails": {"json": "●"}}' lose = JSON.parse(json_black)
Zengo_Master

2020/09/28 19:32

3人の総当たりリーグにおける、json_dataの階層構造は分かりました。 「initのイベント設定時に受け取ったJSON形式の値"○""●"を設定する」が分からないです。
kuma_kuma_

2020/09/28 19:47

一応書いておくとRubyでタグ設定する際直接"○""●"を設定する方法もあります。 ただその場合「結果の保存」をするときに結局JSON形式等変換しないといけなくなります。 処理を統一する為にもJSON形式でのデータの受け渡しとしたのです。 あと前にも書いたけど 「HTML形式で動くものを用意してからRubyに変換する」 なれればRuby上だけで書けるけど相当Rubyをやらないとミスに気が付かなくなったりします。 (HTMLの仕組みも熟知していないといけませんので) めんどくさいようですが、確実に作る手順です。
Zengo_Master

2020/09/29 08:12

以下(一例ですが)がjson_dataの定義ですね。 var json_data = {"_1":{ "member":"Aさん", "_1":{"member":"Aさん","WinOrLose":9}, "_2":{"member":"Bさん","WinOrLose":1}, "_3":{"member":"Cさん","WinOrLose":-1} }, "_2":{ "member":"Bさん", "_1":{"member":"Aさん","WinOrLose":-1}, "_2":{"member":"Bさん","WinOrLose":9}, "_3":{"member":"Cさん","WinOrLose":1} }, "_3":{ "member":"Cさん", "_1":{"member":"Aさん","WinOrLose":1}, "_2":{"member":"Bさん","WinOrLose":-1}, "_3":{"member":"Cさん","WinOrLose":9} } }; これは、対戦前の初期化なので9以外は全て0ですか?
kuma_kuma_

2020/09/29 08:27

回答で書いたのは途中経過時点での内容ですので 質問者様がおっしゃっているように初期値は9以外すべて0です。
Zengo_Master

2020/09/29 09:21 編集

ありがとうございます。以下のようになりました。 var json_data = {"_1":{ "member":"Aさん", "_1":{"member":"Aさん","WinOrLose":9}, "_2":{"member":"Bさん","WinOrLose":0}, "_3":{"member":"Cさん","WinOrLose":0}, "_4":{"member":"Dさん","WinOrLose":0}, "_5":{"member":"Eさん","WinOrLose":0}, "_6":{"member":"Fさん","WinOrLose":0}, "_7":{"member":"Gさん","WinOrLose":0}, "_8":{"member":"Hさん","WinOrLose":0}, "_9":{"member":"Iさん","WinOrLose":0}, "_10":{"member":"Jさん","WinOrLose":0}, }, "_2":{ "member":"Bさん", "_1":{"member":"Aさん","WinOrLose":0}, "_2":{"member":"Bさん","WinOrLose":9}, "_3":{"member":"Cさん","WinOrLose":0}, "_4":{"member":"Dさん","WinOrLose":0}, "_5":{"member":"Eさん","WinOrLose":0}, "_6":{"member":"Fさん","WinOrLose":0}, "_7":{"member":"Gさん","WinOrLose":0}, "_8":{"member":"Hさん","WinOrLose":0}, "_9":{"member":"Iさん","WinOrLose":0}, "_10":{"member":"Jさん","WinOrLose":0}, }, // 途中略 "_10":{ "member":"Iさん", "_1":{"member":"Aさん","WinOrLose":0}, "_2":{"member":"Bさん","WinOrLose":0}, "_3":{"member":"Cさん","WinOrLose":0}, "_4":{"member":"Dさん","WinOrLose":0}, "_5":{"member":"Eさん","WinOrLose":0}, "_6":{"member":"Fさん","WinOrLose":0}, "_7":{"member":"Gさん","WinOrLose":0}, "_8":{"member":"Hさん","WinOrLose":0}, "_9":{"member":"Iさん","WinOrLose":0}, "_10":{"member":"Jさん","WinOrLose":9} } }; if(json_data[arr[1]][arr[2]]["WinOrLose"] == 1){ tds[itd].innerHTML = "○"; } else if(json_data[arr[1]][arr[2]]["WinOrLose"] == -1) { tds[itd].innerHTML = "●"; } 初期値は0ですが、WinOrLoseの値を適当に1や-1に変えても、ページでは○・●が付きません。 そして、if文は例えば、op_1_2の場合だとjson_data[1][2]となり、インデックス参照は0が起点であるため、BさんとCさんの勝負になりませんか?
kuma_kuma_

2020/09/29 09:34

ごめん!コード間違えて古い方張り付けていた! 今修正版アップします。
kuma_kuma_

2020/09/29 09:43

いま修正しました。( // ※ここで設定 から4行) 勘違いさせるようなミスでした。 まずこれで正常に動くことを再度確認しました。 > if文は例えば、op_1_2の場合だとjson_data[1][2]となり、 > インデックス参照は0が起点であるため、BさんとCさんの勝負になりませんか? そうだよねそう思うよね、このJSONキーの値として”_1”とかで持っているから連想配列なんだ 普通の配列なら確かに「0が起点」とかなります。 でも連想配列だからkeywordで取得できるんです。 例 json_data["_1"]["_2"]["WinOrLose"] でも渡している値が前のが間違いで"1"とか"2"だったから誤解を与えてしまったみたいですね すみません。
Zengo_Master

2020/09/29 12:28 編集

ありがとうございます。 連想配列は理解しました。質問を編集し、現在のコードに反映させました。 取消もできるように、クリックしたtdが既に○である場合は、取消になるようにしました。 しかし、取消以前にtdをクリックしても反応がありません。また、斜線を引くところ、ClassListのやり方だとうまく出ません(CSSではコメントアウトして個別指定しています)。 クリックしても○●が出ないのは、function winorlose_clickの中身が問題なのでしょうか?
kuma_kuma_

2020/09/29 21:25

> if(el.target.innerHTML = ''){ 判定は > if(el.target.innerHTML == ''){ だよ 後データの更新の事を考えてjson_data も整合性が取れるように更新すると良いでしょう。 あと "var json_data"の位置はグローバル関数だから1行目に書かないと(Rubyからのパラメータになる) > 斜線を引くところ、ClassListのやり方だとうまく出ません これはどんな症状ですか?
Zengo_Master

2020/09/30 03:17 編集

ありがとうございます。 json_dataは1行目に移しました。更新も考えます。 >> 斜線を引くところ、ClassListのやり方だとうまく出ません >これはどんな症状ですか? jsファイルが読み込めていませんでした。最後に以下を記述すれば反映されました。 window.addEventListener("load", init);
kuma_kuma_

2020/09/30 03:21

こういう時は問題点を整理しよう まずこちらの状態では問題なく動いています。 そうするとHTMLの設定状態がどうなっているか?が考えられます 斜線判定は下記条件で行っています。 > if(arr[1] == arr[2]){ ステップ実行で上の条件は通っていますか?(多分通っていない) それではHTML上 > <td id="cell_1_1"></td> のようにidの登録はありますか(idを”op_1_1”に変えた?変えても大丈夫だけど)? これ斜線だけの問題じゃなくて斜線でクリックすると表示おかしくならない? それとも途中でエラー発生して処理止まっていないですか?
kuma_kuma_

2020/09/30 03:34

元々あった > <body onload="init();"> がRubyに変換する時に無くなったのかな? > <body> window.addEventListener("load", init);
Zengo_Master

2020/09/30 03:50 編集

質問を編集して現在のコードを反映させました。 元々あった > <body onload="init();"> がRubyに変換する時に無くなったのかな? > <body> そもそも、<body>がerbファイルになかったです。 >斜線判定は下記条件で行っています。 >> if(arr[1] == arr[2]){ >ステップ実行で上の条件は通っていますか?(多分通っていない) jsファイルに以下を追加して解決しました。今は正常に動作します。 window.addEventListener("load", init); >それではHTML上 >> <td id="cell_1_1"></td> >のようにidの登録はありますか(idを”op_1_1”に変えた?変えても大丈夫だけど)? cellはすべてopに変えました。htmlとjsで統一しているので大丈夫です。 >これ斜線だけの問題じゃなくて斜線でクリックすると表示おかしくならない? >それとも途中でエラー発生して処理止まっていないですか? 斜線の上でクリックしても何も起きず、その後に斜線以外のところで勝敗記入を行っても正常に動作します。 今のままでは、ページをリロードすると記入した結果が全て消えます。勝敗の情報をデータベースに保存するには、jsファイルでXMLHttpRequestを記述し、コントローラーを経由する方向性ですか?
kuma_kuma_

2020/09/30 03:59

> そもそも、<body>がerbファイルになかったです。 Rubyってそもそも<body>書かないからね... いきなりテンプレートいじるのはハードル高いよね? https://www.javadrive.jp/rails/template/index2.html window.addEventListener("load", init); でもこれは間違いじゃありません。(てか、よくこの方法わかったね。) >cellはすべてopに変えました。 この情報は教えてね。じゃないと不都合の原因特定できないから > 勝敗の情報をデータベースに保存するには、jsファイルで > XMLHttpRequestを記述し、コントローラーを経由する方向性ですか? そうですね。他の方法もありますが基本はその形ですし質問者様が理解なさっているようなので問題ないかと思います。
Zengo_Master

2020/09/30 14:13 編集

質問を編集し、現在のコードを反映させました。 XMLHttpRequestを記述し、コントローラーを経由する方向性ですが、以下の2点で詰まっています。 ①コントローラーでプレイヤーのidはparamsで取得できても、op_(1~10)の情報はどう取得するか? ②反対側のtdをparamsでコントローラーにどう渡すか? もし、現在のコードで方向性が違ったらご指摘お願いします。
kuma_kuma_

2020/09/30 14:22

クリックした時点でセーブにしたのね ・反対側のtdをコントローラーにどう渡すか? ん?○●つける際json_data も更新するんだよ? 更新したらjson_dataを送ってセーブね ・コントローラー側でプレイヤーのidは取得できても ん?これも前のテーブル設計時にid作ったでしょ?その番号だよ
Zengo_Master

2020/09/30 14:46

ありがとうございます。 以下の流れでしょうか? ①どこかのtdをクリックする ②json_dataが書き換わる ③json_dataを更新する ④json_dataをコントローラーに送る ⑤コントローラーがjson_dataをデータベースに反映させる グローバル変数のjson_dataは0だらけ(無勝負の状態)の記述ですが、動的に変化するのですか? json_dataとデータベースのResultテーブルがどう紐付くか分かりません。
kuma_kuma_

2020/09/30 14:54

いやjson_dataの更新処理は入れないと > tds[itd].innerHTML = "○"; または"●"の時 >json_dataとデータベースのResultテーブルがどう紐付くか分かりません。 よく見たら以前提示したテーブル構成じゃないのね... 提示した内容ならその辺りの問題も考慮していたんですが... (人数関係ない設計にしておいたんですよ) どうしようかね...。
Zengo_Master

2020/09/30 15:53

テーブル設計は変えた方が良いですか?
kuma_kuma_

2020/10/01 02:23

う~ん。テーブル設計って設計思想がもろに反映されている部分なんですよ。 変更すれば「こうです」っていうのはたやすい。 ただ質問者様が考えられた「思想」を安易に否定するのもどうかな...となっています。
Zengo_Master

2020/10/01 02:38 編集

教えていただいたjsの記述は、どのようなテーブル設計が前提だったのかが気になります。 現在のデータベース設計だと、json_dataと紐付かないことがまずいんですかね...
kuma_kuma_

2020/10/01 04:49 編集

あれ?質問どこいった? > どのようなテーブル設計が前提だったのかが気になります。 設計段階から今回のJSONを作る目的でHTMLに反映、更新もしやすい。 あと初期データも作成しやすい。次のリーグが始まっても対応できる。勝ち負けSB以外の項目も後から追加できて、今質問者様が作られたTableをSQLで再現できるまで考えています。 でないと意味ないですから。
Zengo_Master

2020/10/01 04:26

テーブル設計に関する質問が過去にありました。 ・総当たりリーグ戦のテーブル設計 https://teratail.com/questions/294350 そこでいただいた参考を踏まえていなかったです。ベストアンサーにしたテーブル設計を踏まえるように作り直しました。 また、それに伴ってコントローラーとビューも修正しました。齟齬が続いて申し訳ございません。
kuma_kuma_

2020/10/01 04:38

DB設計初めてでしょ?じゃ知らないのも当然だから、心配しないで。 DBって処理の基本となる物だから「どんな処理が行われるか」を見越して設計しないと 今回みたいなことになるんだよ。 それも踏まえて「HTMLでまずは動くものを作る」という所から説明したわけ 仕事になるとどうしてもDB設計→HTML作成となってしまうけど、頭の中では逆算しないと 作成する際うまくいかないという事です。
Zengo_Master

2020/10/01 04:44

ありがとうございます。 DB設計をしてから保存の処理を考えるのかと思っていました。
Zengo_Master

2020/10/01 14:45

以下のサイトを参考にしながら進めています。現在のコードを質問編集で反映させました。 ・【Rails入門】JSON.parseでパラメーターをHashに変換する方法 https://www.sejuku.net/blog/74120 リーグ戦にはフォームがありませんが、jsファイルで「submitがクリックされたら」を「tdがクリックされたら」に代替すればよいのでしょうか?
kuma_kuma_

2020/10/01 14:58

質問者様の考え方次第ですが 「tdがクリックされたら」 リアルタイム更新ですが若干処理にラグが発生します 「submitがクリックされたら」 保存ボタンを作成して対応。ただ押下しないと保存できない。 「画面を閉じる時」 通常処理時ラグが発生しない。ただし正しく更新できたかの確認が取れない。 各方法の長所と欠点を上げています。 そのなかで「適切だ」という物をえらんで下さい。
Zengo_Master

2020/10/02 02:29

ありがとうございます。 「tdがクリックされたら」を選びます。
Zengo_Master

2020/10/06 09:17

【Rails入門】JSON.parseでパラメーターをHashに変換する方法 https://www.sejuku.net/blog/74120 上記のサイトを見ても、リーグ戦の連想配列をDBに保存するのは難しいです。何か参考になる書籍などはありますか?
Zengo_Master

2020/10/11 16:12

確認があります。 10人参加の場合で、Resultsデーブルのレコード数は100ですか?それとも斜線のtdを無視で90ですか?
kuma_kuma_

2020/10/12 02:43

>Resultsデーブルのレコード数は100ですか?それとも斜線のtdを無視で90ですか? テーブルの構成上無理に90にする必要はなく100で構わないと思います。 (その為に他箇所で斜線判定等行っているのですから。)
Zengo_Master

2020/10/12 06:06 編集

ありがとうございます。質問を編集し、コードを反映させました。 htmlにある結果記入のtdと、DBのresultsテーブルの結果の全カラムを関連付けました。 XMLHttpRequestを使って、JSファイルを加筆しました。tdをクリックすると、DBのresultsテーブルに◯を保存するところまで実装できました。ページをリロードすると、◯が反映されているようになりました。 しかし、◯の付いたtdをクリックしても消えません(反応なし)。 反対側の●も保存したいのですが、現在のコードで方向性が間違っていたらご指摘いただきたいです。
Zengo_Master

2020/10/12 09:43 編集

ありがとうございます。 送信部分のコードで、以下が引っ掛かりました。 XHR.open("GET", `/results/${resultId}`, false); falseだとDBに保存されず、trueだとDBに保存されます。また、○の付いたtdをクリックすると、空白に変わり、DBに保存されました。 「非同期の場合は、更新順番が必ずしも送った順番にはならない」と教えていただきましたが、だからfalseというのが分かりません。非同期通信がオンならtrue、オフならfalseという認識ですが、falseにしても非同期通信が行えるのですか?
guest

0

質問者様確認しました
内容はコメント※に記載しておきました。
もし動かなくなったのなら、追加した部分を一度コメント化して動作を確認
そこから順番にコメント化の範囲を狭めれば大体のエラー箇所は判ります。

追記
送信を「同期」にするとruby側が応答しないので。
Javascript側で対応

javascript

1 // クリックしたときの処理 2 var send_winorlose = false; 3 var XHR; 4 function winorlose_click(el){ 5 if(send_winorlose) return; // 送信中は実行できない 6 send_winorlose = true; // 処理中とする 7 8 // el にはどこでクリックされたかの情報が入っている 9 var arr = el.target.id.split('_'); // idを'_'で分ける 10 var oppid = arr[0] + '_' + arr[2] + '_'+ arr[1]; // 反対側のid 11 // 勝敗の記入と取消 12 if(el.target.innerHTML == ''){ // 勝敗を記入 13 el.target.innerHTML = '○'; // 勝ち 14 document.getElementById(oppid).innerHTML = '●'; // 負け 15 json_data['_'+ arr[1]]['_'+ arr[2]]["WinOrLose"] = 1; //※jsonのデータ自体を更新 16 json_data['_'+ arr[2]]['_'+ arr[1]]["WinOrLose"] = -1; //※jsonのデータ自体を更新 17 }else if(el.target.innerHTML == '○'){ // 勝敗を取消 18 el.target.innerHTML = ''; // 空白 19 document.getElementById(oppid).innerHTML = ''; // 空白 20 json_data['_'+ arr[1]]['_'+ arr[2]]["WinOrLose"] = 0; //※jsonのデータ自体を更新 21 json_data['_'+ arr[2]]['_'+ arr[1]]["WinOrLose"] = 0; //※jsonのデータ自体を更新 22 } 23 24 var trs = document.getElementById("winorlose_table").getElementsByTagName('tr'); 25 var win = 0; 26 var loss = 0; 27 // 1行目はヘッダーだから飛ばして 28 for(var itr = 1; itr < trs.length; itr++){ 29 // テーブルの行毎に処理 30 win = 0; 31 loss = 0; 32 var tds = trs[itr].getElementsByTagName('td'); 33 for(var itd = 0; itd < tds.length; itd++){ 34 if(tds[itd].id.indexOf('cell_') != -1){ 35 // 勝ち負け数カウント 36 if(tds[itd].innerHTML == '○'){ 37 win ++; 38 }else if(tds[itd].innerHTML == '●'){ 39 loss ++; 40 } 41 } else if(tds[itd].id.indexOf('win_') != -1){ 42 // 勝ち表示 43 tds[itd].innerHTML = win; 44 } else if(tds[itd].id.indexOf('lose_') != -1){ 45 // 負け表示 46 tds[itd].innerHTML = loss; 47 } 48 } 49 } 50 51 //※ データの送信は処理の最後 52 //※ 非同期でも結果が返ってくるまでクリックを無視するように変更 53 let resultId = el.target.getAttribute("data-id"); 54 if(!XHR){ 55 XHR = new XMLHttpRequest(); 56 XHR.responseType = "json"; 57 XHR.onload = function() { 58 send_winorlose = false; // 送信完了 59 }; 60 XHR.onerror = function() { 61 send_winorlose = false; // 送信完了 62 }; 63 } 64 XHR.open("GET", `/results/${resultId}`, true); 65 XHR.send(); 66 }

投稿2020/10/12 07:16

編集2020/10/13 11:01
kuma_kuma_

総合スコア2506

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

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

kuma_kuma_

2020/10/12 10:03

おーいこっちに書いてくれ。そっち長すぎだから。 まず同期にしたら保存されない理由は謎なんだけど... https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests まずOPENのオプションで true = 非同期 false = 同期 です。 同期なので応答があるまで待機しているはずなんですが... request.status === 200でしたか? 同期の理由は<tr>クリック→GET送信→送信結果受信→<tr>クリック可能 としたかったから 非同期だと <tr>クリック→GET送信→別の<tr>クリック→GET送信→送信結果受信(1回目?2回目?) となってしまうため通信状況でサーバに必ず1回目2回目と届くわけではないので 画面と齟齬が発生する可能性があります。(サーバ2回目1回目で届いたら1回目の状態となる) ただfalse(同期)で保存されないのは謎。 ちなみに保存の場合一般的には"POST"だから(変更大変そうだからそのままでも良いよ)
Zengo_Master

2020/10/13 08:38

true=非同期、false=同期と理解しました。後から届いた情報が画面に反映されてしまうんですね。 XHR.send();の後に以下を加えました。 XHR.onload = function (e) { if (xhr.readyState === 4) { if (xhr.status === 200) { console.log(xhr.responseText); } else { console.error(xhr.statusText); } } }; 実行してtdをクリックしても、コンソールに以下が表示されます。 Uncaught DOMException: Failed to set the 'responseType' property on 'XMLHttpRequest': The response type cannot be changed for synchronous requests made from a document. 200が処理成功なので、現状だと失敗ですか?
kuma_kuma_

2020/10/13 08:56

あ~そういう事か... > XHR.responseType = "json"; を > XHR.responseType = "text"; に変更してみて 非同期だとうまくいって同期だとうまくいかない理由もそれ `/results/${resultId}`で送信した際、成功か失敗の結果をjson形式で返していないでしょう? 非同期の場合結果をスルーするから「成功したように見える」だけで結果はエラーだったという事。 たしかtextにすれば返答なしでもエラーにならなっかので一応動くとはおもう。 ただ根本的には`/results/${resultId}`で保存の成功か失敗を文字列かjson形式で返さなといけません。
Zengo_Master

2020/10/13 09:06 編集

質問を編集し、現在のコードを反映させました。 textに変更しても変わりませんでした。 やはり、falseだとDBに保存できなくてtrueだとDBに保存できてリロードするとDBの内容が反映されます。
kuma_kuma_

2020/10/13 10:45

うーん「Ruby on Rails」だと同期処理で送るとページ移動しようとするのね... 「Ruby on Rails」側での回避方法が見つからない...。 よって送信側(Javascript)で対応しましょう。 またソース追記するのでまってて。
kuma_kuma_

2020/10/13 11:04

ここの回答修正したよ。これで大丈夫なはず。(一応ログとか仕掛けて確認してみて) もっと凝った場合処理中は半透明のフィルターかけてなんてするんだけどね。 あとここじゃ実行環境がないので確認して答えられないの、ごめんね。
Zengo_Master

2020/10/13 13:30 編集

ありがとうございます。 質問を編集し、現在のコードを反映させました。 tdをクリックすると○が表示され、反対側に●が表示されました。再びクリックし、結果の取消までできました。現在では、○のみDBに保存され、リロードするとビューに反映されるようになりました。 また、勝敗数に関しても、読み込み時に表示されるようにinitの中身を更新しました(以前はtdをクリックしないと勝敗数が表示されなかった)。 しかし、コントローラーではエンドポイントがひとつしか設定できない(クリックしたtdのidしか送れない)ため、DBで反対側のtdを●に変更する方法が分かりません。以下は、tdの反対側の組み合わせをidで示しました(例:2が○なら、11が●)。 2-11 3-21 4-31 5-41 6-51 7-61 8-71 9-81 10-91 13-22 14-32 15-42 16-52 17-62 18-72 19-82 20-92 24-33 25-43 26-53 27-63 28-73 29-83 30-93 35-44 36-54 37-64 38-74 39-84 40-94 46-55 47-65 48-75 49-85 50-95 57-66 58-76 59-86 60-96 68-77 69-87 70-97 79-88 80-98 90-99 コントローラー側で、この組み合わせを使う方向性で実装できますか?
kuma_kuma_

2020/10/13 14:13

うんやっぱそうなるよね... 質問者様のコードをできるだけ尊重したかったので書かなかったのだけれども... https://www.javadrive.jp/ruby/string_class/index12.html data-idの内容を事前にidと同じように”2_11”にしておく 受信後文字列を分解して処理を行う...。 ([,][-]はURL上好ましくないので使わないように) なんだけど 欲をいえばPOSTでjson送って処理してほしかった...。 そうするとjson形式でのデータのやり取りが完結するでしょ?
Zengo_Master

2020/10/13 15:02

data-idを数字_数字にして、ルートとJSを修正するのですか? routes.rb get 'results/:id', to: 'results#win_or_lose' ⬇️ post 'results/:id', to: 'results#win_or_lose' win.js XHR.open("GET", `/results/${resultId}`, true); ⬇️ XHR.open("POST", `/results/${resultId}`, true); 分解して、コントローラーではひとつ受信するものの、反対側のidを生成するのですか?(例:1_2 ➡️ 2_1)
kuma_kuma_

2020/10/13 15:18

いままでdata-idには”2”,”3”..."35"...."90"とか入っていたのでしょ? それを”2_11”,”3_21”..."35_44"...."90_99"にしてresultIdとかにして送信。 というか前話したテーブル構造だとidと同じ番号で階層構造になっているはずなんだけど...? 前までは result = Result.find(params[:id]) で良かったけどparams[:id]が変わるから resultAry = params[:id].split("_") とかしてidを分離すれば反対側のidも判るでしょ? そうしたら「●」の位置わかるよね? それもめんどくさいならparams[:id]から計算で反対側を取得すれば良いのでは? (PHP上の計算とおんなじでしょ?)
Zengo_Master

2020/10/14 07:32

ありがとうございます。 質問を編集し、修正後のコードを反映させました。 data-idを数字_数字(例:2_11)に変更し、コントローラーで分解する手法で実装できました。 順位はエクセルのRANK関数のように実装したい(全員の勝ち数のうち、その人の勝ち数は何番目に多いか)のですが、JSではどのような実装になりますか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問