hogashi.*

日記から何から

今週の頑張り

 一から Webアプリを作ったことがなかったので、現在地の情報を勝手にエディンバラに付けてツイートする Webアプリを作って勉強した。 Ruby 使っているけど Ruby あんまりわからないので雑。

github.com

 まずツイートしたいと思って、簡素にできると聞いていた Sinatra を使って、 apps.twitter.com でキーを 4つとも取得してコードに直書きして、 Twitter gem で OAuth 完了状態にしておいてツイートしたりした。Twitter::REST::Client.newにキー4つを渡すのだけど、 Twitter gem の使い方はなんとなくインターネットを見てやっているので正しいのかわからないけどリクエストはできている、みたいな状態。
 Twitter のアプリのキーを 4つとも取得して置くのは本当は違って、アプリ固有のキー (2つ)でユーザ固有のキー(2つ)を取得する、みたいなことをするのが OAuth で、以下で直していくけど、とりあえずツイートしたかったのだった。

 現在地情報は、Twitter::REST::Tweets#update の引数に渡すオプションのハッシュに latlong で緯度経度を指定すればよいらしいのでやったけど、できなくて、色々やっていたら place という方に Twitter::Place を渡すとできた。
 渡す Twitter::Place は、 Twitter::REST::PlacesAndGeo#geo_search で取ろうとしたけど、なんか情報がたくさん要るらしくてわからなくて、 Twitter::REST::PlacesAndGeo#similar_places のほうに、緯度経度をlat, long、「Edinburgh」という地名を name で渡した。
 これでエディンバラの場所情報がついたツイートができた。

 テンプレートを書いて、formからPOSTでリクエストしたらtextareaの中身をツイートするようにした。paramsにフォームの内容が入っていて、textarea[name="text"]ならparams[:text]で取れて、それをツイートする。

 なんとなくツイートできるようになったので、 OAuth したくなったのだけど、 Twitter gem にあるTwitter::REST::OAuthは使い方がよくわからなかったのでインターネットを見たら、 OmniAuth というのがよいという話だった。 Sinatra 公式が例として上げているくらいなのですごそう。実際に使うのは omniauth-twitterFacebook とかもあるらしい。
 アプリのキー2つConsumer Key (API Key)Consumer Secret (API Secret)を使って、ユーザのキー2つAccess TokenAccess Token Secretを取って、ユーザごとにTwitter::REST::Client.newするみたいな感じになる。
 OmniAuth で理解に苦しんだところは、肝心の OAuth するところで /auth/twitter とかいうエンドポイントにリダイレクトするけど、そのエンドポイントは定義してないじゃん、というところで、実はコメント文をよく見ると書いてあって、/auth/twitterは OmniAuth が拾うので、投げるだけでよいらしい。
 リクエストは投げられるけど Sinatra が 403 エラーを出すのでインターネットを見たら、 apps.twitter.com のほうでアプリの callback URL をちゃんと指定しないとそうなるらしかったので、したら直った。これ難しくて、 403 とだけ出されても、特に解決方法がわからない。 callback URL は、この場合ドメイン/auth/twitter/callback とするようになっているけど、多分なんでもよくて、beforepass if request.path_info =~ /^\/auth\//のところで引っ掛けたいから/authで始めている、というだけだと思う。ドメイン/koorubakku というふうにして、pass if request.path_info =~ /^\/koorubakku/とか足せば良いんだと思う。
 あとそもそも pass if request.path_info =~ /^\/auth\// にうまく引っかかってない感じがあって、無限に認証しまくるループになったりした。いや引っかかってるのかもしれないけど pass が上手くいってないのか、 pass がそもそも何なのか知らないので、何もわからなくて、使うのやめて、素朴に if で条件分岐するようにした。しかも、そもそも勝手に認証してほしくないので、before も使わなくなる(後述)。
 あと認証済みかどうかを保存するのにsessionというハッシュに突っ込んでおくようにしたけど、なんか Rack のセッションらしくて、よくわかっていない。なんかうまいことセッションをやってくれるんだと思う。あんまりなんでもかんでも突っ込むと、容量オーバーして怒られるので、最小限にする必要があるけど、ツイートごとにユーザを認証したりするのは絶対おかしいので、Twitter::REST::Clientは入れておくようにした。合ってるのか全然わからない。

 これで大体動くようになってきて、テンプレートにログイン/ログアウトボタン足したりした。

 ここでツイートをするのに毎度ページ遷移(見た目は変わらないけど毎度読み込んでる)するのはもったいないなと思ったので、JavaScript でPOSTリクエストすればいいか、となり、それなら axios が良いですよ、と教えてもらったので使った。POST リクエストは上手くパラメータが取れなかったので、GET リクエストにしている。ちゃんと勉強すればできるんだと思うけどちょっと勉強したくらいでは解決できなかった。

 あとの問題は公開で、サーバのこともよくわかってないので、ここの勉強もいずれはしたいけど、今回は良いかと思ってしまったので、 Nginx のこと勉強したりせずに、 Heroku にデプロイすることにした。 Procfileweb: bundle exec ruby app.rbとかやればいいらしいのだけど、Thin というサーバが小さくて便利だよとインターネットに書いてあったので開発中にも使っていて、そのまま使おうかなという気持ちになったので、bundle exec thin -R config.ru -p $PORT start とか書いた。 $PORT は勝手にセットされるらしい。開発環境で何もしていしないと 5000 番になった。 Heroku なら Heroku 側が好きなように渡してくれるんだと思う。
 Heroku で yarn installとかyarn run buildとかしてもらいたくてインターネット見たら、Heroku の Settings で Buildpacks ってところに Node.js を足せばよいらしいと書いてあって、そうした。yarn run heroku-postbuild とかを実行してくれるので、package.jsonに書いておくとやってくれる。今回は webpack 使ったので、それをやってほしかったのだった。
 これでちゃんと HTTPS で配信されるし便利。

 こういう気持ちで webpack.config.js 書いてるのか~とか、エンドポイントってこういう感じに切ると便利なのか~とか、少しずつ学びがあってよかった。今回は特に CSS はやっていないし、 Ruby とサーバは分かってないのでそこは勉強が必要。