| @技術/プログラミング
[1] pry(2.0.0-p195)> require 'open-uri'
[2] pry(2.0.0-p195)> require 'active_support/core_ext/hash/conversions'
[3] pry(2.0.0-p195)> Hash.from_xml(open('http://www.portalshit.net/index.atom').read)
=> {"feed"=>
  {"xmlns"=>"http://www.w3.org/2005/Atom",
   "id"=>"http://www.portalshit.net/",
   "title"=>"portal shit!",
   "updated"=>"2013-06-18T19:07:44+09:00",
   "link"=>
    [{"type"=>"text/html",
      "rel"=>"alternate",
      "href"=>"http://www.portalshit.net/"},
     {"type"=>"application/atom+xml",
      "ref"=>"self",
      "href"=>"http://www.portalshit.net/index.atom"}],
   "entry"=>
    [{"id"=>"tag:www.portalshit.net,2013-06-18T19:04:33+09:00",
      "title"=>"Alfred で Chrome のブックマークを検索する",
      "published"=>"2013-06-18T19:04:33+09:00",
      "updated"=>"2013-06-18T19:07:44+09:00",
      "link"=>
       {"type"=>"html",
        "rel"=>"alternate",
        "href"=>
         "http://www.portalshit.net/2013/06/18/chrome-bookmark-search-with-alfred"},
      "content"=>
       "<p><img src=\"https://resources.portalshit.net/945-chrome-bookmark-search-with-alfred.png\" alt=\"945-chrome-bookmark-search-with-alfred.png (708×295)\
      "author"=>{"name"=>"morygonzalez"}},

で XML の内容を Hash にできる。ActiveSupport 便利。

| @技術/プログラミング

jQuery Validation で特定のイベントに対してだけバリデーションを無効にする方法が分からなくて困ってた。例えばフォームの中の送信ボタンではなくキャンセルボタンが押されたときにはバリデーションを行わずにフォームを送信したいということがあると思う。

調べていたら以下の記事がひっかかった。

input タグの class に "cancel" を指定すれば validate されないとある。ほかに、ボタンの click イベントとかで

$("form").validate().cancelSubmit = true;

と書いてやっても良いみたい。こちらは JavaScript で form を submit() するタイプのやつにも使えて使い勝手良さそう。

jQuery Validation 、便利だけどドキュメントが充実してなくてつらい。あとどれが公式か分からないのもつらい。去年くらいまで jQuery Plugin のサイトにドキュメントあった気がしたんだど今は別のサイトに単独で存在してる。

| @雑談

思うに、若いときは一番給料低くて、お金ないから、暮らせてたら節約する必要ない、どうせ今の若い人とか30歳までに死ぬから、それまでに貯金しても仕方ない、万が一長生きしても、相応に技術が高まってれば収入も上がるはずだから、健康を維持できれば取り返せる、ので、僕は今は特に貯金しようといった考えない。今けっこう本買って勉強したり書いてるコードも悪くないと思ってるから、これで若いときに貯金してなくてお金なくなって死ぬようなら理不尽だと思う。ハードモードすぎる。変に無理して節約しようとして精神が異常になるほうが損だと思う。

健康 - hitode909の日記

ヒトデさんの言うことは正しい。能力の高い人は高価な技術書を買って自己投資して将来荒稼ぎできるので週五日タクシーで山奥まで行ったり高級Tシャツ買ったりしても大丈夫だと思う。

残念ながら普通の人はそうはいかない。普通の人は将来自分が荒稼ぎできる自信がないので若い頃からちまちまお金を貯めるしかない。普通の人は無理して節約せず浪費したときの方が不安が高まって精神に異常を来してしまう。

僕は会社の若者に蓄財を説いたことがあるけど、この若者は有能だから僕のアドバイスは間違っていたかもしれないと思った。世の中には金を貯める必要がある人と貯める必要がない人の二通りがいる。

| @労働

RubyKaigi 、2010 年のに行ってすごく感化されて 2011 年も 2012 年の Sapporo も行きたかったけど結婚するといろいろあってそういうのは無理だった。当然のように今年も無理だった。恐らく自分は終生 RubyKaigi には行けないのだと思う。ああいうプログラミングのイベントに熱心に参加したり運営の方に回ったりする人は本当にすごいと思う。みんなそれぞれ家庭とか奨学金の返済とか住宅ローンとかあるんだろうけど、時間をやりくりしてコミュニティ活動を行っている。

受託の会社にいた頃、技術とかどうでも良くて言われたとおり作って金がもらえるならそれでいい、というような情熱がない感じの人だらけの職場がとても嫌だった。しかしいま自分が彼らのようになりつつあるように感じる。悪い感じにサラリーマン化している。このままでは新卒とか有能な若者にあっという間に追い越されて老いさらばえていくだけだと思う。それは分かっているけど 30 歳くらいになるといろいろ厳しい。

| @技術/プログラミング

Lokka でキャッシュしたいと書いてたけどキャッシュできるようになった。

結局 sinatra-cache を使った。sinatra-cache、2 年くらいメンテされてなくて全然だめかなと思ってたけどドキュメントが執拗なほど詳しく書かれてて使い方がわかりやすかったので使ってみることにした。フラグメントキャッシュがページごとに共有されなくて非効率的だったところは適当に改造した(morygonzalez/sinatra-cache · GitHub)。

footer 部分だけキャッシュするようにしてるのでトップページのレンダリングはあまり変わってないように感じる。個別記事ページは HTML が返ってくるまで 2, 3 秒かかってたのが 500ms から 600ms くらいになった。割とよいと思う。

いまのところ cache の有効期間みたいのを設定できないのでこれを任意の時間で設定できるようにしたい。しばらく使ってみて問題なさそうだったら Lokka 本体に Pull Request してもよいかも。

| @技術/プログラミング

以前、Unicorn が暴走して困ってるという記事を書いていた。しかしよくよく調べてみると暴走してるのは Unicorn ではなく、Syntax Highlight に使っている Python の Pygments を呼び出している Ruby のプロセスだった(pygments.rb)。こいつが CPU をバカ食いしてしまい、アプリケーションのレスポンスがすこぶる悪くなっていた。

少し前、Pure Ruby の Pygments 互換 Syntax Highlighter で Rouge というのを発見していたので、Python を spawn するプロセスがなくなれば CPU バカ食いも止まるはず、と思って pygments.rb から移行してみた。しかし…

なんと逆にサイトが重くなってしまった。やはり Pure Ruby のプログラムは重いみたいである。pygments.rb は C のネイティブコードも含んでいて、速さがボトルネックになるところは C で処理しているみたい。

というわけで残念ながら EC2 のマイクロインスタンスで Rouge を常用するのは無理そうなので Pygments + pygments.rb に戻します。あとはキャッシュして誤魔化すしかなさそう。

| @技術/プログラミング

一月くらい前から Lokka の master ブランチを自分のブログ用のブランチに merge してサイトをデプロイすると謎の白画面が出るようになっていて困っていた。現象は極めて謎で、ローカルの開発環境(RACK_ENV='development')では見られず、本番(RACK_ENV='production')だけで発生した。HTTP ステータスコードは 1054 が返ってきたりする。なんか変な gem でも入れてしまったかなと休みの日に動作検証したりしていたんだけどついぞ分からなかった。

SQL 弱者なので気がついてなかったんだけど、2月15日の commit で Site モデルに新しいフィールドが追加されていた(Add default markup in admin/site/edit · 2243dc5 · lokka/lokka ※この機能便利すね)。なので bundle exec rake db:migrate しないといけなかったわけだった。ローカルで動いている開発環境(データベースは SQLite)では Migration なんて行ってないんだけどエラーは出なかった。本番は MySQL で動いていて、こちらでだけエラーが出るようだった。

しかしいざ migrate しようとすると失敗する。

bundle exec rake db:migrate
Upgrading Database...
rake aborted!
Invalid default value for 'updated_at'

のようなエラーが出る。updated_at のデフォルト値がおかしいらしい。このときのテーブルの構造を見てみると以下のような感じだった。

mysql> desc entries;
+-----------------+--------------+------+-----+---------------------+-----------------------------+
| Field           | Type         | Null | Key | Default             | Extra                       |
+-----------------+--------------+------+-----+---------------------+-----------------------------+
| id              | int(11)      | NO   | PRI | NULL                | auto_increment              |
| user_id         | int(11)      | YES  |     | NULL                |                             |
| category_id     | int(11)      | YES  |     | NULL                |                             |
| slug            | varchar(255) | YES  |     | NULL                |                             |
| title           | varchar(255) | YES  |     | NULL                |                             |
| body            | text         | YES  |     | NULL                |                             |
| type            | text         | NO   |     | NULL                |                             |
| draft           | tinyint(1)   | YES  |     | 0                   |                             |
| created_at      | timestamp    | NO   |     | 0000-00-00 00:00:00 |                             |
| updated_at      | timestamp    | NO   |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |
| frozen_tag_list | text         | YES  |     | NULL                |                             |
| markup          | varchar(255) | YES  |     | NULL                |                             |
+-----------------+--------------+------+-----+---------------------+-----------------------------+

調べてみたところ MySQL の Mode が NO_ZERO_DATE になっている場合、MySQL は timestamp 型のフィールドのデフォルト値に 0000-00-00 00:00:00 みたいな値を設定することを許さないらしい。 mysql - Invalid default value for 'create_date' timestamp field - Stack Overflow

検証用に別にテーブルを用意して bundle exec rake db:setup してみたところ、以下のような構造のテーブルができた。

mysql> desc entries;
+-----------------+------------------+------+-----+---------+----------------+
| Field           | Type             | Null | Key | Default | Extra          |
+-----------------+------------------+------+-----+---------+----------------+
| id              | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| user_id         | int(11)          | YES  |     | NULL    |                |
| category_id     | int(11)          | YES  |     | NULL    |                |
| slug            | varchar(255)     | YES  |     | NULL    |                |
| title           | varchar(255)     | YES  |     | NULL    |                |
| body            | text             | YES  |     | NULL    |                |
| markup          | varchar(255)     | YES  |     | NULL    |                |
| type            | varchar(50)      | NO   |     | NULL    |                |
| draft           | tinyint(1)       | YES  |     | 0       |                |
| created_at      | datetime         | YES  |     | NULL    |                |
| updated_at      | datetime         | YES  |     | NULL    |                |
| frozen_tag_list | text             | YES  |     | NULL    |                |
+-----------------+------------------+------+-----+---------+----------------+

created_atupdated_atdatetime 型になるらしい。なので以下のような ALTER 文を実行した。

mysql> alter table entries modify column created_at datetime, modify column updated_at datetime;
mysql> desc entries;
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
| user_id         | int(11)      | YES  |     | NULL    |                |
| category_id     | int(11)      | YES  |     | NULL    |                |
| slug            | varchar(255) | YES  |     | NULL    |                |
| title           | varchar(255) | YES  |     | NULL    |                |
| body            | text         | YES  |     | NULL    |                |
| type            | text         | NO   |     | NULL    |                |
| draft           | tinyint(1)   | YES  |     | 0       |                |
| created_at      | datetime     | YES  |     | NULL    |                |
| updated_at      | datetime     | YES  |     | NULL    |                |
| frozen_tag_list | text         | YES  |     | NULL    |                |
| markup          | varchar(255) | YES  |     | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+

これで最新のコードをデプロイしても真っ白画面になることはなくなった。以前遭遇した更新時に created_at の値が更新されてしまう問題 もフィールドの型が timestamp だったのが原因なのだと思う。SQLite から MySQL への移行は一筋縄では行かないことが分かった。

DataMapper はソースコード内の記述内容から動的に Migration を行えるけど、ActiveRecord みたいに $APP_ROOT/db/ ディレクトリに Migration ファイルを作ってくれたりしないので DB スキーマの変更が必要なことに気がつきにくい。便利だけど不便な感じがする。Rails で $APP_ROOT/db/ 以下にアホみたいにファイルが出来ていくの嫌だと思っていたけど、スキーマ変更に気がつかずコードをデプロイしてウェブアプリケーション停止みたいな自体は防げると思った。

ブログ書こうと思ってパソコン開いて「ついでに最新版の変更を取り込むか」とかやるとデプロイできなくなったりして書きたかった記事が書けず残念な感じになる。はてなブログでブログ書いてて画面が真っ白になったらひとでくんさんに不具合報告して直してもらえば良いので楽だと思う。