素人が2020年までの1ヶ月でLINE BOTに挑戦する毎日note. 【Day 29:開発5日目_LINEログイン後にDBからデータを取得してマイページを表示】
こんにちは。くろです。
12月1日から2019年残り1ヶ月でスケジュール調整BOTの開発に挑戦しています。今日は29日目です。
福井にスノーボードに行ってきたのですが、残念ながらとてつもない暖冬で雪が全くなく人工雪のすごい小さいコースが1つだけという悲しい状況でした。。。
とはいえ昨年は一度もできなかったので、シーズンインできて良かったなとは思います。
スキーっていうよりはゴルフ場感。笑
本題です。
早くも29日目なんですが、まだLINEログインしてマイページを表示する所も終わってないです。
【お詫び】
あまり認めたくはなかったのですが、この後年末の予定を考えると、どう考えても間に合わないです。
結構悔しいですね、、、DBのEntityあたりからはもう設計よりも開発に入ればよかったのというのと、結構エラーや上手く行かない時に一旦諦めて違う方法をやるとかそういう諦め方も大事だったかなと思います。。。
年内もうあと2日で、時間もあんまり取れないんですが、なんとか日程調整を作る所までは終わらせたいなと思います。
また、せっかく毎日更新していて、平均すると60PVくらい読んでくださっている方もおられますし、12月中これをやるために迷惑かけた人たちもいるので、年内は難しくなりましたが、完成まで開発は続けていきたいと思います。
また、完成までにやるべきことはnoteにまとめていくので、読んでいけばLIINEBOTの完成までの道のりが学べるnoteとして仕上げてはいきます。
何卒よろしくお願いします。
【難しかったこと】
・やはり基本的なコードとかお作法がざっとインプットできていないと何がだめなのかの見当がつかない&どうやったらできるかの見当がつかない。
・わからなかった時に検索するけど、なかなか答えが見つからない。
herokuの標準DBぽかったからpostgresqlを選んだけど、mysqlの記事の方が多かったり。。というかpostgresqlの記事はあるんですが、今回の環境における記述の仕方が書いているものとかがなかったりするので、そこが難しかったです。
・LINEBOTの場合、デバック(試行錯誤)がいちいちデプロイして確かめないといけないから、ちょっとコード変えて試して結果見て、っていうのに2分くらいかかってしまう。単なるWEBだとローカルで一瞬で見れたりするので。
特にデバックが時間かかるのとざっとインプットできてないので、時間がすごいかかってしまった感じはあります。
インプットの所は例えばExpressの記事をもっと早くに読んでいれば、どうやってアプリケーションが動くのかわかっただろうし、postgresqlやDBについては今でもあんまりわかってないので、結構辛いものがありますね。。
あとは、当たり前ですが、本業の合間に普通にいろんな予定を入れながらだと時間がそんなに取れなかったというのは実感したことです。
とはいえ、まだ続くので、暖かい目で見守ってください!
概要
開発アプリ:Googleカレンダーと連動してスケジュールを調整してくれるLINEBOT
BOTの概要:Day 2の記事に書いています。
BOTの仕様:機能一覧やフローチャート Day 10の記事に書いています。
BOTの開発環境:Day25の記事でアプリケーションの骨格を作りました。
昨日はDBにユーザーデータを保存してDBへデータを保存する所まで書きました。
今日はDBからデータを取得してマイページを表示する所まで書きます。
2-3,マイページ作成
データを表示するために、簡易的にマイページ(=トップページと同じURLでやろうと思ってます。)を作っておきます。
index.ejsにhtmlでこんな感じの文を入れました。
<div><h1><%= user_name %><span>さん。こんにちは</span></h1></div>
<%= hogehoge %>でindex.jsからこのejsをrenderした時のオプションにhogehoge = XXと設定することで、hogehogeに値を入れることができます。
また、これまでは一度トップページに来てからLINELOGINさせていましたが、トップページに来たらLINELOGINしておいて欲しいので、トップページのapp.get('/', hogehoge)も編集して、/loginにリダイレクトさせるようにします。
.get('/', (req, res) => res.redirect('https://scheduler-linebot.herokuapp.com/login'))
本当は毎回ログインページに飛ばすんじゃなくてログイン状態が維持されていたらLINELOGINいちいちしなくても次に進んで欲しいんですが、ちょっとそこは諦めます。というか一回ログインしてたら勝手にそうなるもんやとおもてた。
そうなると、index.ejsのLINELOGINボタンの行は不要なので、コメントアウトしておきます。
const linelogin_uid_insert = {
text: 'INSERT INTO users (line_uid) VALUES($1)',
values: [JSON.parse(body).userId],
}
ほんでここの下にトップページをオプション付きで表示するような指示を書きました。
//後でSELECTしてDBから持ってくるように変更
res.render('pages/index', {
user_name:JSON.parse(body).displayName,
})
{}の中のuser_name: JSON.parse(body).displayNameでさっき取ってきたdisplayNameが入ったbodyを読み出して、名前を格納しました。
これでトップページにアクセスするとLINELOGINが走って、その後ユーザーの名前が入った状態でトップページにアクセスさせることができるようになりました。
ただ、これはログインした時に取ってきた情報を出してるだけでDBから取り出した訳ではないので、2-4でDBからデータを取り出してuser_nameに格納します。
2-4,DBからデータを取得してマイページに表示2-2,DBへユーザデータを保存
一旦名前が出てくるようにはなったけど、マイページを普通に開いたときにはでてこないので、でてくるようにしないと、、、
ということで、SELECTでDBから該当のデータを取ってきて、それをindex.jsからindex.ejsに受け渡して表示させよう!と思います。
と思ってこういうクエリを書いてみたのですが、なんかいやってもエラーになって、ここで結構な時間を取られてしまいました、、、
usersというテーブルからline_uidが${JSON.parse(body).userId}のやつを取ってきてねというクエリ文です。${JSON.parse(body).userId}は、LINELOGINした時に取ってきたline_uidです。なので今ログインしたuserIdと同じ文字列がline_uidカラム(列)にあれば、そのline_uidがある行の内容を教えてねっていう指示ということになります。
connection.query(`SELECT * FROM users WHERE line_uid = ${JSON.parse(body).userId}`)
.then(res => console.log(res)
.catch(e => console.error(e.stack))
で、いろいろ試しまくった結果、
${JSON.parse(body).userId}を''で囲めば通ることがわかりました!祝!!
connection.query(`SELECT * FROM users WHERE line_uid = '${JSON.parse(body).userId}'`)
.then(res => console.log(res)
.catch(e => console.error(e.stack))
VARCHARの時はそうしないと通らないぽいです。なぜならidの数字だとそのままでも通ったからです。
次は返ってきたresの内容を使ってindex.ejsをレンダリングするだけなのですが、このデータの取り出し方でまた詰まっていました。。。
なにをどうやってもエラーがでて、2時間くらい格闘していたのですが、ちょっとしたミスがあったことを発見してそれを変えると、通りました!!
DBから取り出した名前を表示することができました!
function index_render(display_name) {
res.render('pages/index', {
user_name: display_name,
})
}
connection.query(`SELECT * FROM users WHERE line_uid = '${JSON.parse(body).userId}'`)
.then(res => {
console.log("res.rows[0].display_name", res.rows[0].display_name);
index_render(res.rows[0].display_name);
})
.catch(e => console.error(e.stack))
先にindex.ejsをレンダリングする関数を作っておいて、それをconnection.queryの中で呼び出しています。
その中で呼び出さずに、connection.queryの中で、aaa = res.rows[0].display_nameとかを入れておいて、
その後にindex_render(aaa)とかを実行しても、aaaがconnection.queryの中でしか代入されていないので、使えませんでした。
もしくは非同期処理だからかもしれないです。
とにかく中で呼び出す必要がある!ということがわかりました!
結果がこちら。
・メモ
よろしければサポートお願いします! 頂いたサポートはクリエイター活動に活用させて頂きます。