Sinatraアプリを素のRackアプリケーションに書き換えた
Rackとは
Webサーバ/Webアプリケーションフレームワーク間のインタフェースの役割を果たすライブラリで、 Rackを利用してフレームワークやアプリケーションのインターフェース部分を実装することで、 Webサーバを変更したり、逆にWebサーバを変更しないでもRackでインタフェースを実装されたフレームに置き換えることができる。
Rubyだと、WEBrickやUnicron、PumaにPassengerといろいろなアプリケーションサーバがあるけど、 多少挙動に違いがあるにせよ、RailsやSinatraといった性質の異なるフレームワークが殆どのアプリケーションサーバで稼働するのは Rackでインタフェース部分を実装されているからである。
他の言語
むしろRubyのRackは後発で、Pythonで既にあった、WSGIに影響されて実装されたと言われている。 PerlではPSGIがそれに相当する。*1
Rackについてぼんやりと理解していたけど、 このあたりに乗っているリンクを眺めて更に理解を深めることができたので、興味があると見てみると良いでしょう。
アプリケーションを実際に書き換えてみた。
Rackってそう言えばちゃんと触ったこと無いな〜と思ったので、とりあえず触ってみることに。
なんかちょうどいい感じのSinatraアプリケーションのogp_parse_apiが転がっていたので、 今回はコレをSinatraから素のRackアプリケーションに書き換えて見ることにする。 ogp_parse_apiについては、過去のブログに機能的には詳しく書いているので、よかったら見てくれ。
というわけで簡単に作ったアプリケーションをRackだけで書き換えてみた。 ルーティングするものも1つしか無いし、機能が全く無いのであっさりできた。
これに取り組んだ大きなモチベーションとしては、技術的なアドバイスをくれる人がいるのだけど、 その人がとある案件の対処法にRackでアプリケーション書いて対応しようとした。 という話を聞いたのがきっかけで、Rubyエンジニアで2年弱やってきているのに、 素のRackアプリケーションを書いたことがないのは、 Rubyエンジニアとしてモグリなんじゃないのかと思えて焦りを感じてるし、素振りがてらやってみた。
good-bye sinatra by webuilder240 · Pull Request #1 · webuilder240/ogp_parse_api · GitHub
書き換えてみてよかったこと
- Sinatraの依存から開放された。
- 他のGemに依存しているので、まあ誤差だと思うけど。
- それ目線で言うならDockerイメージをalpineベースにしたり、nokogiriに依存するGemをなくす方が先。
- Rackのことがなんとなくわかった、ちょっとは仲良くなれた。
- 本当に単機能であればRackで書くのもありかなと思いました。
- 今後nodejsとかやngx_mrubyに置き換えるのも見据えるようなアプリケーションの場合、それよりも敷居が低い素のRack実装は、調べることも少なくある程度はパフォーマンス稼げるし取り掛かりとしていいのかなと。
- 速度は未計測...
まとめ
まぁ本当に素振りでやったのでただの自己満足です。 ただ、こういう適当に遊べる環境を持っておくのは大事だと思いました。
*1:AuthorはRebuild.fmでおなじみの宮川さんです。
javascript経由で<script>タグを呼び出して実行する方法
これやりたい経緯
静的ファイル上でユーザーエージェントを判別して、広告タグを出し分けたいというのを実現するための方法と一つとしてです。 本当は配信先の広告タグスクリプトでよしなにやっててほしいんですが、 そういうわけにも行かないときはやっぱりあるので...
サンプルコード
jsfiddleにでも置きたいと思っていたのだけど、jsfiddleでは複数ファイルのスクリプトの実行をサポートしていないように見えたので、 とりあえずgistにでも置いておく。 まぁ、結果から言うと普通に出来た。
load dynamic execute script tag
まとめ
ただ、配信先の広告タグをコレでよしなに出し分けれたとしても問題があるかもしれないし、 収益に関わる案件なので、導入は慎重に行きたい。
毎週技術的なブログを書く為に実践していること
今年のお正月からなんとなく毎週ブログを更新するというのを初めて10回を超えたので自分なりに振り返ってみようと思う。
ネタ探しについて
まだ10回なんだけど、業務内容にも恵まれてるのかもしれんがぶっちゃけあまり困ってないです。 ネタはたくさんある方だと思っているけど、裏を取るために動かしたり色々調べたりするのがとにかく面倒...*1
過去にやって見たことを引っ張り出してる。
別に技術ブログには「今やっていること」「将来やりたいこと」を書くというレギュレーションはない。 三年前に書き散らしたコードをブラッシュアップしてブログに出す、のでもいいと思う。
自分の記事だと、 これは投稿した時点よりも2〜3ヶ月前にライブラリの素体は出来上がっていたので、 ブログに投稿する記念にHerokuにデプロイとDockerイメージとしてPushしたくらいで、他に特別なことはしていない。
自作ライブラリについてをブログに書く
自分で便利で作ってみたライブラリとアウトプットを両立するためにライブラリを書くだけじゃなくて、 日本語でもいいから、説明をブログに残しておくというのはいい方法かもしれない。 自分はまだ経験ないけど、誰かに見つけてもらって使ってもらう...なんてこともあるかもしれないし。*2
アップデートした場合は、アップデートについて書くのもいいかもしれない。 些細なアップデートでも立派なアウトプットである。
本当に些細・ニッチなものでもとにかく投稿してる
忘れてはならないのは、「バズ」のために記事を書いているわけではないということだ。 自分の書いたブログはひたすらはてブ0がならんでいるし、承認欲求を満たすことは出来ていない。 個人的にムカつくのでリンクは貼らないけど、 Qiitaにあるような「フロントエンドの用語・技術だけを雑に集めた雑なリンク集」がブックマークを集めるのが昨今の現状である。
とにかく、他人の評価は気にせずに、自分で正しいと思ったことをとにかく続けることに専念しよう。 承認欲求に関しては、まぁブックマークきたらうれしいねーくらいにしておいたほうが良いかもしれない。 webuilder240.hatenablog.com
最初の一歩を大事にする為に...
かける時に書けるだけ書く、でも欲張らない
とにかく馬力があるときにまとめて7割位まで書けるときは書いてしまったほうが良いと思っている。 書きたいことだけをブログに下書きでつらつら並べておいて、 その後はその項目について調べたりで終わるくらいにするのが一番いいと思ってる。
誘惑に負けない方法
明らかにモンハンをやってる時期は手を抜いていた。 手を抜くことはわかっていたので、軽めの記事で「とにかく繋ごう」と言う気持ちで、 あっさり目のものを書いたり、先に書いた通り、事前に8割方書けるときに貯金しておくという方法で乗り切った。
誘惑に負けない方法は個人的には無いと思っており、 「好きなことを好きなときにやる」のが一番なので、その時は「しっかりゲームで遊ぶ」ことを最優先にしてました。 またプログラミングばかりやるフェーズはやってくると思っているので...
今の所モンハンに200時間くらい時間を溶かしてるけど、無理なく続いてる。*3
今はとりあえず続けるだけを目標にしているだけなので、半年か1年続けたらやめようと思ってる。
やめたあとは定期投稿でなくていいので、アウトプットの質を高める方をやってみようかなと思っている。
FirestoreをRubyのgoogle-api-clientから叩く
そもそもRubyからFirestoreを叩きたい理由
- FirestoreはフロントエンドからWriteできるけど、実装の複雑さを避けるためにフロントエンドからはWriteしないで、 チャットのAPI経由でFirestoreに対してWriteを行う機構が必要だったため。*1 *2
方法
ここまでの方法は調べればいくらでもあるので、他の記事等を参考にして進めて欲しい。 ちょっと画面がややこしいので、この部分を含めても解説しても良かった気がするが時間がないので、また追記します。 以降は実際にコードとしてどう書けばいいか、というのを雑に並べておきます。
require 'google/apis/firestore_v1beta1' SCOPE = ['https://www.googleapis.com/auth/datastore', 'https://www.googleapis.com/auth/cloud-platform'] PROJECT_ROOT_PATH = "projects/hoge-project/databases/(default)" client = Google::Apis::FirestoreV1beta1::FirestoreService.new client.authorization = Google::Auth::ServiceAccountCredentials.make_creds( json_key_io: File.open("#{Rails.root}/config/hogehoge.json"), scope: SCOPE ) message = Message.first # firestoreにドキュメントを追加 def push_firestore(message) client.create_project_database_document_document("#{PROJECT_ROOT_PATH}/documents", 'messages', message_doc(message)) end # firestoreの指定したドキュメントを削除 def destroy_firestore(firestore_message_id) client.delete_project_database_document("#{PROJECT_ROOT_PATH}/documents/#{firestore_message_id}") end # firestoreのフィールド設定 def message_doc(message) doc = Google::Apis::FirestoreV1beta1::Document.new() doc.fields = { "id": { integer_value: message.id }, "content": { string_value: message.content }, "created_at": { timestamp_value: message.created_at.rfc3339 }, "updated_at": { timestamp_value: message.updated_at.rfc3339 } } doc end
これでとりあえずgoogle-api-client経由でドキュメントの作成と削除ができる状態になった。 ほかにもたくさんFirestoreのAPIがあるみたいなので、それはまた今後眺めてみることにする。
感想
- 特にexampleのコードとかなかったし、とにかくわかりづらい印象だった。Gemの中身をちゃんと読みまないと絶対にわからん。
- 各項目に対して型を設定するのがいちいち面倒、ちゃんと使う分には何某かのうっすいラッパーくらいあっていいかも。
参考リンク
*1:あとは私がサーバサイドエンジニアだったのでというのも理由ひとつ
*2:参考: https://speakerdeck.com/sota1235/realtime-messaging-with-firebase-number-phpcon2017
自作のサービスのsinatraのバージョンをアップしました。
ogp_parse_apiというサービスを適当に運用・Dockerイメージを提供しているのですが、 こちらで利用しているSinatraで脆弱性の修正を含むバージョンアップがあったのでその対応をしました。
ogp_parse_apiは単純にOGP情報をスクレイピングしてJSONで表示するだけの単純なサービスです。 詳しいことはこちらの記事をご参照ください。
経緯
こんな感じでGithubから通知が到着していた。
どうやらSinataraの脆弱性の修正が含んだバージョンアップがあったらしく、 そのためSinatraをアップデートしてくれーと通知欄に来ていたので対応しました。
やったこと
至極簡単で、
bundle update
とbundle exec rspec
をやってテストが通ったので、コミットして、GitHubにPush。 さらにHerokuにDeployして作業終了。 簡単なアプリケーションだけど、テストを書いているので安心感をもってリリースできたのでテスト書いててよかった。