社内ハッカソンで使うアンケート結果収集ぺージをNode-REDで作ったので、備忘録的に書きます。
はまりどころにはまったので、三時間ぐらいかかりました。。。
コピペなら、アカウントを用意するところから始めても30分ぐらいでできるはずです。
背景
「メンバーにアンケートをとって、回答データを元に人員最適配置を考える」というソリューションのモックアップを作ることになりました。
ここに書くのは、動作概要1,2にある、入力データをWeb画面からとってきてDBに格納する部分のソースコードです。
"質問回答ページ"フローのHTMLをお好みで修正すればいろいろな目的のWeb入力ページとして応用できます。
前提環境・用意するもの
- IBM Bluemix の無料アカウント (詳しくはここに書いてます )
- IBM Bluemixの Node-REDのプロジェクト(ボイラープレートで、「Internet of Things Platform Starter」 を選択。詳しくはここに書いてます )
- IBM BluemixのCloudantサービス (こことか わかりやすいです。)
- Webブラウザ(今回はFirefox)
- テキストエディタ(今回はサクラエディタ)
基本的にタダで!!
動作概要
- Web画面でユーザーがアンケート回答を入力する。
- 回答結果をJSON形式でCloudantに格納する
- (結果はCloudantを直接覗いて華麗にデータ分析する by IBM Data Scientist Experience (DSX) (担当外))
セットアップ方法
- https://(Noderedのプロジェクト名).mybluemix.net/red/ にアクセスして、ソースコードをインポートします。(Node-RED画面の三本線アイコン>Import > Clipboard のダイアログにソースコードを丸ごと貼り付けます)
- Cloudantフロー(水色)をダブルクリックして、DBのURL、認証情報を自分のDBの設定に書き換えます。
- Deployボタンを押してアプリケーションを更新します。
使い方
http://(Node-REDのプロジェクト名).mybluemix.net/answerget
にアクセスすると、アンケート回答ページが表示されます。
回答して"Submit"ボタンを押すと、回答結果がJSON形式でCloudantに格納されます。
やっていること
- GET : アンケートページの表示。
- アンケートページに仕込んだjavascript : 画面で指定した入力結果をJSON形式に変換して送信
- POST : 送られてきたデータをCloudantに突っ込む
はまりどころ
header設定が必要
”headerの小細工”フローの処理を入れておかないと、データが送れません。
ドメインをまたぐときのセキュリティ設定を明示的に解除します。
msg.headers = {
"Access-Control-Allow-Origin":"*",
"Access-Control-Allow-Method":"GET,POST,PUT,DELETE,OPTIONS",
"Access-Control-Allow-Headers":"Origin, X-Requested-With, Content-Type, Accept"
}
return msg;
アンケート回答ページにはhttpでアクセス
↓にhttpsでアクセスしてたらエラーになった。(横着してNode-REDのURLを基にした). Firefoxのコンソールログ(F12押す)でエラーログが確認できます。
http://(Node-REDのプロジェクト名).mybluemix.net/answerget
フローのイメージ
ソース
Node-REDの三本線アイコン>Import > Clipboard で以下のテキストを貼り付けると読み込めます。CloudantのURL、サービス名、APIキー、パスワードは自分用のCloudantの設定に書き換えてください。
[{"id":"270a7cf.9b4a184","type":"http in","z":"d0bfacd3.26b4d","name":"/answerpost","url":"/answerpost","method":"post","swaggerDoc":"","x":141,"y":265,"wires":[["1931547f.3a3d8c","c5d5fdb6.862e8"]]},{"id":"1931547f.3a3d8c","type":"debug","z":"d0bfacd3.26b4d","name":"","active":true,"console":"false","complete":"payload","x":341,"y":218.5,"wires":[]},{"id":"b2aff6a4.bf0e38","type":"http response","z":"d0bfacd3.26b4d","name":"","x":672,"y":274.5,"wires":[]},{"id":"2d844b0.5f7b6b6","type":"http in","z":"d0bfacd3.26b4d","name":"/answerget","url":"/answerget","method":"get","swaggerDoc":"","x":133,"y":99.5,"wires":[["539fffff.1d36b","fcdc058b.6b8c78"]]},{"id":"539fffff.1d36b","type":"debug","z":"d0bfacd3.26b4d","name":"","active":false,"console":"false","complete":"true","x":287,"y":51,"wires":[]},{"id":"f56c3564.947238","type":"http response","z":"d0bfacd3.26b4d","name":"","x":656,"y":121,"wires":[]},{"id":"c5d5fdb6.862e8","type":"function","z":"d0bfacd3.26b4d","name":"headerの小細工","func":"msg.headers = {\n \"Access-Control-Allow-Origin\":\"*\",\n \"Access-Control-Allow-Method\":\"GET,POST,PUT,DELETE,OPTIONS\",\n \"Access-Control-Allow-Headers\":\"Origin, X-Requested-With, Content-Type, Accept\"\n}\n//正常終了\n//msg.payload = {\"message\":\"Success insert\"};\nmsg.statusCode=200;\nreturn msg;","outputs":1,"noerr":0,"x":357,"y":280,"wires":[["55c79e9b.5bd86","53d800fd.c81f2"]]},{"id":"8ffbe37e.4e84b","type":"function","z":"d0bfacd3.26b4d","name":"headerの小細工","func":"msg.headers = {\n \"Access-Control-Allow-Origin\":\"*\",\n \"Access-Control-Allow-Method\":\"GET,POST,PUT,DELETE,OPTIONS\",\n \"Access-Control-Allow-Headers\":\"Origin, X-Requested-With, Content-Type, Accept\"\n}\n//正常終了\n//msg.payload = {\"message\":\"Success insert\"};\nmsg.statusCode=200;\nreturn msg;","outputs":1,"noerr":0,"x":501,"y":123.5,"wires":[["f56c3564.947238"]]},{"id":"fcdc058b.6b8c78","type":"template","z":"d0bfacd3.26b4d","name":"質問回答ページ","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>あなたの恋愛感は?</title>\n<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js\"></script>\n\n<script type=\"text/javascript\">\n $(function(){\n $(\"#response\").html(\"Response Values\");\n\n $(\"#button\").click( function(){\n var url = $(\"#url_post\").val();\n\n var JSONdata = {\n uname: $(\"#uname\").val(),\n a1: $('#answerform [name=a1]:checked').val(),\n a2: $('#answerform [name=a2]:checked').val(),\n a3: $('#answerform [name=a3]:checked').val(),\n a4: $('#answerform [name=a4]:checked').val()\n };\n\n //alert(JSON.stringify(JSONdata));\n alert(\"回答を送信しました!!\");\n\n $.ajax({\n type : 'post',\n// url : url,\n url : '/answerpost',\n data : JSON.stringify(JSONdata),\n contentType: 'application/json',\n dataType : 'json',\n scriptCharset: 'utf-8',\n success : function(data) {\n\n // Success\n //alert(\"回答を送信しました!!\");\n //alert(JSON.stringify(data));\n $(\"#response\").html(JSON.stringify(data));\n },\n error : function(data) {\n\n // Error\n //alert(\"error\");\n //alert(JSON.stringify(data));\n $(\"#response\").html(JSON.stringify(data));\n }\n });\n })\n })\n</script>\n\n</head>\n<body>\n <h1>あなたの恋愛感は?</h1>\n \n<form id=\"answerform\" method=\"POST\">\n <p>お名前: <input type=\"text\" id=\"uname\" name=\"uname\" size=\"50\" value=\"\"></p>\n <p>追いかける恋がいい: <input type=\"radio\" name=\"a1\" value=\"1\" checked=\"checked\" >1 <input type=\"radio\" name=\"a1\" value=\"2\" >2 <input type=\"radio\" name=\"a1\" value=\"3\" >3 <input type=\"radio\" name=\"a1\" value=\"4\" >4 :追われる恋がいい</p>\n <p>面白くて飽きない人: <input type=\"radio\" name=\"a2\" value=\"1\" checked=\"checked\" >1 <input type=\"radio\" name=\"a2\" value=\"2\" >2 <input type=\"radio\" name=\"a2\" value=\"3\" >3 <input type=\"radio\" name=\"a2\" value=\"4\" >4 :一緒にいると癒される</p>\n <p>ルックス重視: <input type=\"radio\" name=\"a3\" value=\"1\" checked=\"checked\" >1 <input type=\"radio\" name=\"a3\" value=\"2\" >2 <input type=\"radio\" name=\"a3\" value=\"3\" >3 <input type=\"radio\" name=\"a3\" value=\"4\" >4 :人柄重視</p>\n <p>プロポーズはド派手なサプライズ: <input type=\"radio\" name=\"a4\" value=\"1\"