Seiichi Yonezawa

“How creativity is helped by failure”

開発日記 #20

今日はこのサイトのマイナーチェンジに取り掛かってみました。

まずはいまいち使いこなせていなかったTurbolinksをクラシック版に変更しました。というのも、RailsガイドTurbolinks 5のAPIが微妙に異なっているようでTurbolinks 5を使えるようになるのが一番いいのですが、今はまだアップローダとかのほうに興味が向いているので暫定的にクラシック版を使おうと思います。このサイトのビジュアル的にはプログレスバーがうまく合っているんですが、どのサイトも標準でプログレスバーを出すようになった5はちょっとなぁと思ったり。

続いて現在はまだ振り分け作業を全く行っていないので少々寂しいですが、画面右側のナビゲーションにタグを振り分けることにしました。それぞれの投稿が多い順に10件表示するデザインですが、これの実装が正直大変でした。最近になってようやくSQLを読めるようになってきたレベルの私にとって、has_many :tags, :throughで関連づけられた投稿をgroupするまでが一苦労でした……。試行錯誤の末ようやく使えるようになったものの、まだ肝心のビュー関連に手をつけていないのでそちらはおいおい対応していく予定です。

開発日記 #19

昨日は感謝祭、そして今日はBlack Fridayですね。セールなので欲しいものがいろいろあるのですが、本命はグラフィックボードなのでどうしようかなと悩んでいたりします。

Ubuntuサーバーが再稼働したので、本格的にRailsを簡易的なファイルサーバーとして管理しようと思ったのですが、だいたい800MBくらいのファイルサイズのものを直接アップロードしようとするとどうやらRailsがハングアップしてしまうようです。しかし、ローカルの開発環境からアップロードするだけなので、そこまでファイルの容量には影響を受けないと思っていたのですが、どうやらそうでもなさそうでした。昨日はShrineやRailsで直接ファイルアップロードを試みたのですが、1MBなら問題ないのでやはりサーバーそのものに問題がありそうです。

そこで、StackOverflowを見てみると、S3を使えばいいという回答を除外すると、代替案として考えられるのはFTPやBitTorrent、tusなどのプロトコルの変更や、jQueryFileUpload、mod_porterというものがあるようです。

I've also had good luck using jQuery-File-Upload, which supports good stuff like chunked and resumable uploads. Without something like mod_porter, this can still tie up an entire thread of execution during upload, but it should be decent on memory, if done right. This also results in a file that is "close" and, as a result, easy to process. This approach will require adjustments to your view layer to implement, and will not work in all browsers.

この回答の一部分を引用すると、jQueryFileUploadはチャンクアップロードに対応しているというので、こちらはmod_porterが不要らしいです。ブラウザのBlob形式のAPIを利用するのですべてのブラウザが対応しているわけではなさそうですが、正しくやると求めている結果に近くなるそうな。そこで、参考になりそうな投稿がありました。

File.open(path, "ab") { |f| f.write(p[:upload].read) }

チャンク型なのでファイルを"ab"で追記していく部分に感銘を受けました。
800MB近くのtmpfileをそのまま'wb'しないのがポイントですね。

if @upload.nil?
  @upload = Upload.create(params[:upload])
else
  if @upload.upload_file_size.nil?
    @upload.upload_file_size = @temp_upload.upload_file_size
  else
    @upload.upload_file_size += @temp_upload.upload_file_size
  end
end

また、レスポンスヘッダにチャンクのサイズ等を返すための前処理でしょうか。
ifが入れ子なのが少し気になりますが処理そのものは明快です。

とりあえずはこれを試してみる方面でいこうと思います。これがうまくいけばShrineやどのgemを使っても動きそうなので。

開発日記 #18

まだ計画段階ですが、今日は開発日記部分を公開としてログイン等の管理機能を分けようと思いました。これ自体は以前もやっていたのですが、モノリスが良い時もあれば、細かく分割したい時もあります。そして、現状はやっぱりわざわざ一括りにするほどのものでもないのかなと思えています。少なからずログインが公開側にある、すなわち検索エンジンにヒットすることは不毛に思えます。一番不満だったのはBootswatchのテーマは気に入ってるのですが、レイアウトがいまいち満足できないので、また別のテーマを拾うことにしました。何を採用したかはまた改めて公開したときにでも。それではまた明日。

開発日記 #17

昨日と今日は主に自宅サーバに使うRailsを書いていました。開発日記#15でも触れていますが、今までSambaやGitLabなどファイルサーバくらいしか用途がなかったのですが、これを少し拡張してRailsでサーバ管理できるようにすればいいんだと思いつきました。非常にシンプルなサイトなのでこれもまだしばらくオープンにする予定は現在ありません。そこで、ファイルのやりとりを簡略化するためにShrineというGemを使うことにしました。今まではPaperclipを利用していましたが、単に利用するだけならImageMagickをインストールしなくても依存関係はなさそうなので、軽快です。ただし、ShrineはRodaにインスピレーションを得ているようで、モジュラー化していて使いやすそうですがその反面自分でいろいろと定義しなければならないのでこれも習得には少々時間が必要かもしれません。なんだかこういうプロジェクトが面白くなってきて、GameOffはやっぱり今週もできませんでした。さすがに残りの日数でできるものも限られてくるので、事実上のリタイア宣言をここに残しておきます。敗因はやはり、この文章を書いていてもインスピレーションが湧かなかったからかも。また来年にあれば今度はもう少しJavaScriptを身近にしてから再挑戦したいですね。

開発日記 #16

以前マイクロサービスに関して考えたのですが、あまり記憶にとどまらないうちに忘れてしまいました。というのも、何が必要で何が不要かとか、具体的なイメージが湧きませんでした。今日もまだそんな感じなのは変わらないのですが、また再び昨日書いたRailsやSinatraを考えるとそろそろマイクロとモノリスについて考えてもいいのかなと思えてきました。

Sinatraは何と言ってもフットワークが軽く感じます。Railsの起動が3秒だとすると、Sinatraは1秒くらい。ただ、やっぱり書いているとRailsがトータルで便利に思えるのですが、そもそもせっかくSinatraは各種テンプレートをサポートしてるんだし、登録はしなくともレンダリングに担当させてしまうのもいい気がします。
そして、さんざん作りたいを繰り返しているエディタはJSの力を借りて、並列処理にElixirなんていうような投稿を読んで、それに感化されつつあるような。


その後RabbitMQをインストールしてみました。お約束のHomebrew経由ですが、依存関係にErlangがもれなくついてくることを知りました。そして、"Hello World!"のチュートリアルに挑戦してみました。単純な相互関係の通信をするはずが、何故かメッセージを受信できるのは一度きり?RedisのPubSubではすぐにレスポンスが返ってきていたので、若干不安に思えました。もう少し読み進めたほうがよいかもしれません。それに、マイクロサービス間の通信は結局HTTP経由でやることを前提にしているのでいかんせんまだRabbitMQの使い道が想像できていません。

開発日記 #15

最近になってSinatraの楽しさを再発見しつつある私ですが、Railsも書いています。というより、今日はRailsを書きました。GameOffではモチベーションが全くわかないのとは対照的に、Railsだったら10コミットも余裕です。やっぱり慣れなんでしょうかねぇ。

さて、Railsでいつか使いたいと思い続けていた#gigabyteというメソッド。これは期待通りに動きます。

1.gigabyte #=> 1073741824

少々見慣れない数字なんですが、1073741824 / 1024 / 1024 / 1024 = 1なので、KB、MBそしてGBという感じです。素敵ですね。また、ヘルパーメソッドに#number_to_human_sizeというものがあって、こちらも期待通りに利用できます。

helper.number_to_human_size(1.gigabyte) #=> "1 GB"

あら素敵。これも機会があれば使いたかったんですが、なかなかファイルそのものをDBとかで扱うこともなかったんですよね。今日はRailsでファイルを管理するようなサイトを作っていました。

開発日記 #14

今日の開発日記は残念ながらあまり書きたいほどの内容はなかったのですが、ぼちぼちGameOffを書き始めました。ただ、JavaScriptもゲーム書くのも嫌いではないはずなのに、なぜか書いていて楽しくないという。せめて今日明日のうちにゲームの骨組みだけでも完成しておきたかったのですが、骨組みはおろか、まだろくにプレイできそうな環境ですらありません。うーん、今回は気持ちばかりが先行してしまって本当に書きたい内容がわからないのかもしれません。このブログに注力する前はそこそこJavaScriptも書けていたはずなのですが、なかなか難しいものです。

開発日記 #13

昨日は早めに就寝し、今朝は謎のテンションでクイズを進めていました。それで、なんとか第一段階としては完成といえると思うのですが、相変わらずGameOff関連は何もできておらず。試験の勉強しなければならないのに部屋の掃除が捗るような、そんな中学生の心境です。それで、第二段階として考えているのは、もともとクイズを作ることが目的ではなく、「クイズを作り出すファイル」を作るのが目的だったりするのです。いわゆるDSLです。

そこで、このクイズに内部DSL、いわゆるRubyでinstance_evalすればすぐに出来そうに思っていたのですが、これをこのサイトにアップロードできる形にしてしまったら、例えばこんなことができるんだろうなと妄想しました。

system "rm -rf *"

なんと恐ろしい。これは極端な例ですが、require "net/http"とかを実行して踏み台にされたり、Sequelを内部で実行されて、データを勝手に挿入したり、参照されたりしそうです。実際に取り掛かる前に気づけて良かったんですが、どんなにセキュリティに気を付けたとしてもパスワードにpasswordと指定するようなものなんじゃないかなと。

また悪意の有無に関わらず、文法のエラーやメソッドの使い方等、例外処理をうまく処理するのもなかなか大変そうです。もちろん、begin節で区切れば全て解決というわけでもなさそうですし、ローカルで、自分だけで使うなら構わないようなものですが、ある程度の権限をユーザーに委譲しなければならないというのはなかなか並大抵の苦労では測れないものだと思います。TravisなどのCI系のサービスやHerokuなどのプラットフォームも、迷惑行為などと日夜対策に迫られているのかもしれません。

なんだか暗い話題になりかけてしまっているのですが、今回はクイズの問題を設定したり、ルームの設定を指定するだけなので、そんなに難しいことはしないのかもしれませんが、やはり思いつくだけテストを書かないといけないし、そこまでして作りたいとは思えません。それに、そもそもRubyは内部DSLだからこそ輝くのであって、外部DSLではこの言語を選ぶアドバンテージがあるのかどうか怪しいです。Webで単語を検索しても、Rubyで外部DSLを記述する方法はあまり触れられていません。

もともと練習のつもりで作る予定でしたが、本番の方はこちらはこちらでローカルで実行させられる形式で提供するので内部DSLでも問題ありません。そして、このクイズに問題を追加する形式はRailsのnested_attributesのようにフォームを追加していく形式にすると思われます。こんな課題をなんだか昔にも考えた記憶がある気がしますが……。とりあえずはもう少し後になると思われますが、このプロジェクトももう少し続けたいと思っています。

開発日記 #12

今日はGameOffの言及をしておきながら、まずはこのブログに報告されていたセキュリティの不具合を修正しました。というのも、開発日記 #9で作った変換機能で以下のようなコードがあったためです。

converter = Converter.new(strong_params)
converter.type.constantize.find(strong_params[:id]) if converter.valid?

この機能は管理権限でないとできないアクションなので、さほど問題ではなかったのですが、そのままパラメータのtypeをconstantizeしてしまっていたので、ユーザーが作為的な値を送信してきた時に云々。

もともとvalid?でもtypeの有無しか確認していないデタラメっぷりなので、typeが予め登録してある値かどうか確認することにしました。結局コードの本質はそこまで変わらないのですが、一応は解決できました。

続いて、今度こそGameOffに取り掛かるかと思いきや、また別のことがやりたくなって新しくSinatraのプロジェクトを作成し始めました。いくら締め切りが今月末とはいえそこまで余裕があるとは思えませんが……。肝心のプロジェクトの進捗具合はそこそこでした。まあ、集中は出来たので、成果はあったんじゃないかなとは思っています。

しかし、Sinatraだけでもまだ完成していないで手元に残しているだけでも数えて4つあります。それぞれがある程度いいところまで進んでいるんですが、満足に動いているとはいえない状況です。それに加えてGameOffという大きなイベントが控えているので、本当に大丈夫なのかと我ながらに思ってしまうわけですが、今週はそんな細々したプロジェクトを進めつつ、今度こそGameOffに集中できるようにしたいです。

開発日記 #11

昨日はGameOffからフォークしたリポジトリを進めようと思ったのですが、何故かあまり捗りませんでした。どうも、webに関わる内容なら何時間でも書ける気がする反面、何か新しいことに挑戦しきれていない気がします。とはいえ、JavaScriptでゲームというのもwebに関わっていることには代わりないはずなのですが……。

その代わりに何をしていたのかというと、Sinatraを書いていました。最近事あるごとにRailsばかり書いてきましたが、先週から書いたクイズでSinatraを書き始めてから改めて良さを再認識できたような感覚です。ただ、SinatraはRailsに比べるとテストが若干書きにくいのがネックなのですが、Railsのテイストを取り入れることで、前とは比べ物にならないくらい書いてて面白さがありました。ただし、link_tocontent_tag等の便利なヘルパがすぐ使えないのが厄介ですね。かといって、それを使えるようにRailsから引っ張ってくるのも色々と厄介です。以前勉強会でやったRailsにSinatraをマウントするようなことをすればいいのかもしれませんが、やっぱりSinatraはその軽快さが好きなのです。

昨日はせっかく早起きしたのに、夜更かしをしてしまったせいで今日はまた出だしから良くない感じになってしまいましたが、今日はこれからGameOffに取り組んで少しは進捗できればいいなと思っています。