一から Webアプリを作ったことがなかったので、現在地の情報を勝手にエディンバラに付けてツイートする Webアプリを作って勉強した。 Ruby 使っているけど Ruby あんまりわからないので雑。
- ここで公開しています: https://hello-edinburgh.herokuapp.com/
- Heroku の無料のやつなので寝起きは遅いです
まずツイートしたいと思って、簡素にできると聞いていた Sinatra を使って、 apps.twitter.com でキーを 4つとも取得してコードに直書きして、 Twitter gem で OAuth 完了状態にしておいてツイートしたりした。Twitter::REST::Client.new
にキー4つを渡すのだけど、 Twitter gem の使い方はなんとなくインターネットを見てやっているので正しいのかわからないけどリクエストはできている、みたいな状態。
Twitter のアプリのキーを 4つとも取得して置くのは本当は違って、アプリ固有のキー (2つ)でユーザ固有のキー(2つ)を取得する、みたいなことをするのが OAuth で、以下で直していくけど、とりあえずツイートしたかったのだった。
現在地情報は、Twitter::REST::Tweets#update
の引数に渡すオプションのハッシュに lat
と long
で緯度経度を指定すればよいらしいのでやったけど、できなくて、色々やっていたら place
という方に Twitter::Place
を渡すとできた。
渡す Twitter::Place
は、 Twitter::REST::PlacesAndGeo#geo_search
で取ろうとしたけど、なんか情報がたくさん要るらしくてわからなくて、 Twitter::REST::PlacesAndGeo#similar_places
のほうに、緯度経度をlat, long
、「Edinburgh」という地名を name
で渡した。
これでエディンバラの場所情報がついたツイートができた。
- Module: Twitter::REST::Tweets — Documentation for twitter (6.2.0)
- Module: Twitter::REST::PlacesAndGeo — Documentation for twitter (6.2.0)
テンプレートを書いて、form
からPOST
でリクエストしたらtextarea
の中身をツイートするようにした。params
にフォームの内容が入っていて、textarea[name="text"]
ならparams[:text]
で取れて、それをツイートする。
なんとなくツイートできるようになったので、 OAuth したくなったのだけど、 Twitter gem にあるTwitter::REST::OAuth
は使い方がよくわからなかったのでインターネットを見たら、 OmniAuth というのがよいという話だった。 Sinatra 公式が例として上げているくらいなのですごそう。実際に使うのは omniauth-twitter
。 Facebook とかもあるらしい。
アプリのキー2つConsumer Key (API Key)
とConsumer Secret (API Secret)
を使って、ユーザのキー2つAccess Token
とAccess 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
とするようになっているけど、多分なんでもよくて、before
のpass 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 にデプロイすることにした。 Procfile
に web: 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 とサーバは分かってないのでそこは勉強が必要。