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

こういうコード書いてます。

function getAttrName(attrObj) {
    var attrName = attrObj.firstChild.data;
//  items = document.getElementsByClassName('item');
    var items = $('li.item');
    $(items).fadeOut('slow');
    for (var i = 0; i < items.length; i++) {
    //  var keywordList = items[i].getElementsByClassName('keyword-list');
        var keywordList = $('.keyword-list', items[i]);
        for (var j = 0; j < keywordList.length; j++) {
            //var keywords = keywordList[j].getElementsByTagName('li');
            var keywords = $('li', keywordList[j]);
            for (var k = 0; k < keywords.length; k++) {
                if (attrName == keywords[k].textContent) {
                    $(items[i]).fadeIn('slow');
                }
            }
        }
    }
    getCurAttr(attrName);
}
function getCurAttr(attrName) {
    var curAttr = $("#keySelector li a");
    for (var l = 0; l < curAttr.length; l++) {
        if ($(curAttr[l]).text() == attrName) {
            $(curAttr[l].parentNode).addClass('current-keyword');
        } else {
            $(curAttr[l].parentNode).removeClass('current-keyword');
        }
    }
}

やりたいことは以下のような感じ。

  1. onclickで attrObjgetAttrName に渡される
  2. クリックされた文字列を attrName に格納
  3. すべての item をjQueryを使って非表示
  4. item の中の ul.keyword-list li 内のテキストに一致したらjQueryで表示

Firefox/Safari/Operaでは問題なく動く。しかしIEが全滅。最初は getElementByClassName とか使ってるからかと思ってたけど、その辺のやつをコメントアウトしてjQueryセレクタを使ってオブジェクトを取得するようにしてもダメ。なんかループの処理とかが怪しいんじゃないかと思ってる。ループ処理もjQueryに書き換えようかな。

ブラウザ間の挙動の違いを吸収してくれるライブラリはまじですごいしありがたいのですが、結局IEちゃんでは動かせない。歯がゆいな。

サーバーサイドで実装する方法もないではないけど、

  1. いじる部分が広範囲になりめんどい(新たなバグが発生するかも)
  2. 大した機能じゃないのに大手術したくない
  3. ずっとPHPばっかり触ってるのはつまらん

などという理由により期限ぎりぎりまでJavaScriptで粘ってみたいです。

追記

"Twitterでcxxさんに教えてもらった":http://twitter.com/cxx/status/13545498622 んだけど、IEにはtextContetはないそうです。恥ずかしい。

そういうわけで

var keywords = $('li', keywordList[j]);

var keywords = $('li a', keywordList[j]);

とし、

if (attrName == keywords[k].textContent)

if (attrName == keywords[k].firstChild.data)

にしてみたところ、ばっちりIEで動くようになった。

cxxさんありがとうございます。今度焼き肉デートしましょう。

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

ポータルシットがクソ重くて、なんか対策ないかなーとか仕事をさぼりながらときどき調べてた。

おおよその原因は掴んでいた。それはアクセス解析プラグイン。MySQLのデータ容量がでかくなるとページの表示が遅くなる。アクセス解析プラグインを無効にした状態でページの表示速度はだいたい0.05秒くらいなんだけど、アクセス解析プラグインを有効にすると表示速度は1秒台とかまで悪化する。アクセス解析に使うテーブル( p_page_analyze )をDROPするとまた速さが回復するので時々空にしていた。

しかしよくよくアクセス解析プラグインのコードを覗いてみると、ヴュー部分で使っていないSQLクエリが発行されており、このせいでクエリの回数が必要な回数の何倍にもなっていた。ポータルシットのアクセスなんて大したことないんだから、DBのサイズがちょっとでかくなっただけでこんなに遅くなるはずがないのだ。

そういうわけで不必要なクエリのトリガーになるコードをコメントアウトしてみた。すると1秒台だった表示速度は0.2秒から0.5秒程度に収まるようになった。しかしそれでもなんか遅く感じる。

それでキャッシュを効かせることにしてみた。使ったのはPecl APC。DreamHostはなんでもやらせてくれるのでほんと助かる。

Pecl APC - DreamHost を見ながらシェルスクリプトをコピペして走らせ、php.iniにAPCの設定を書き加えて終了。僕はPHPのバージョンを5.3.1に上げているのでコピペしたシェルスクリプトのまんまではきちんと入らなかった。最新版のAPC(APC-3.1.3p1)にバージョン情報を書き換えてインストールしたところうまくいった。またDreamHost Wikiではキャッシュファイルのパスが /home/username/tmp/apc.*XXXXXX* だったり /home/username/tmp/apc.*XXXXX* だったりばらついてるけど、Xの数は6個じゃないと500エラーが出るのでご注意を。

キャッシュを効かせて見た結果、フッターのPage Generationはあまり変化がないが、体感速度は十分に速くなった。

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

CakePHP 1.3のStableがリリース された。 JavascriptヘルパーとかAjaxヘルパーが非推奨になってる 。かわりにHtmlヘルパーのjsメソッドを使うらしい。 $html->js('') みたいな感じかな。で、Ajax系の処理はjQueryがデフォルトのライブラリになったらしい。Rails 3.0もprotorype.jsに別れを告げたらしいし、自分がJavaScriptのライブラリで遊び始めた頃はjQueryが全盛だったのでいまからprototype.jsの使い方勉強するのかったるかったし、jQuery簡単だしこの進化は大歓迎です。

JavascriptヘルパーとAjaxヘルパーが非推奨になった件については、わざわざ別のヘルパーにせんでもいいよなー、という印象は確かに持ってた。Htmlをいじるメソッドは一つのヘルパークラスにまとめてしまった方がすっきりする。1.2.xのときはAjaxヘルパーが使いづらすぎて結局jQueryでAjaxすることもあったし、あまり存在意義を見いだせなかったので良かったんじゃないでしょうか。

でも既存のプロジェクトの1.3への移行はめんどくさそうなのでたぶんやんない気がする。新しくCakePHPでなんか作るときは使ってみようと思います。

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

CakePHPには Media Plugin というのがあって、これがすこぶる便利。画像や文書の他に、動画ファイルまで扱うことができる。PHPではファイルアップロードのところにセキュリティリスクが潜んでいそうなイメージだし、自分のような素人に毛が生えたようなレベルの人間は素直にこういう便利なプラグインを使った方がいい。

しかしこのMedia Plugin、設置が少々面倒だ。情報も英語のものも含めて少ない。僕は二つのプロジェクトでこのMedia Pluginを使ったけど、とても設置に苦労した。はまるポイントはいくつかあるんだけど、今日はDBについて書いておこうと思う。

Media Pluginは attachments というテーブルをつくり、ここにファイルのメタデータを格納していく。これはアプリケーションのルート( APP ディレクトリ)で cake media init というコマンドをTerminalで打ってやると(ただし /cake/console にパスを通しておく必要あり)、Bakeのときのような画面が出てきて初期設定をやってくれる( app/config/database.php の情報にあわせてテーブルも作ってくれる)。しかしCakePHPのデフォルトDBがMySQLであるためMedia PluginもMySQLを想定しているのか、 app/plugins/media/config/sql/media.sql のSQL文を単純に実行してしまうと不具合が生じる。実は僕はここで結構はまってた。僕は全部のプロジェクトでSQLiteを使っているので、単純にこのSQLを実行すると、 attachments.id のデータ型が INT(10) とかになってしまい、エラーに遭遇し続けることになってしまった。SQLiteの場合、idカラムのデータ型は INTEGER でなければならないのだ。

これはMedia Pluginに限らないけど、Convention Over Configuration なフレームワークを使うときは、DBのテーブル名に注意をはらわなければならない。否、先にも書いたとおりそれだけでは不十分で、さらにカラムのデータ型とかも規約に沿ったものにしないと、原因不明の謎のエラーに遭遇して開発が停滞する。おっちょこちょいな人(僕も含めて)はその辺の基本的な部分をおろそかにしない方がいいと思った

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

なんかTwitterで「最近のポータルシット変わったよね…」とかいう意見を目にするようになったので、パソコンネタだけ隔離して別にブログを始めることにした。使っているCMSはMephisto。Railsの勉強になるかと思って。早速DreamhostへMephistoをインストールしていて躓いてしまったのでちょこっとメモ。

とりあえず tech.portalshit.net というサブドメインを用意し、DreamhostのパネルでPassengerのセットアップ。その後SSHでサーバーに接続し、

$ git clone git://github.com/emk/mephisto.git
``

してgithubからプロジェクトをclone。

Mephistoのインストールにはいくつかgemが必要。Dreamhostには結構たくさんgemがインストールしてあるんだけど、いくつか足りないものがあった。とりあえず設置ディレクトリのルートで

```sh
$ rake gems:install

と打ってみたところ、nokogiriとそれに依存するbrynary-webratが入らなかった。原因を調べてみたところ、xsltのライブラリをダウンロードして、gem install するときにパスを指定してあげる必要があるらしい。xsltのライブラリ自体はPHP5をカスタムインストールしたときに入れてあるので、以下のオプションでインストールした。

$ gem install nokogiri \n    --with-xslt-include=/home/morygonzalez/php5/include/ \n    --with-xslt-lib=/home/morygonzalez/php5/lib/

無事インストール成功。その後もう一回 rake gems:install を実行してbrynary-webratも入り、管理ページにアクセスしてみると今度はPassengerのエラーが。これは単純にdatabase.ymlに development: のDB環境しか記述していなかったこと、 rake db:bootstrap のときに RAILS_ENV=production をつけていなかったことが原因だった。そういうわけでdatabase.ymlに production: の設定(sqlite3を使用)を書き、

$ rake db:bootstrap RAILS_ENV=production

ですべてのインストール作業完了。いまこうして動いております。

今後はここにCakePHPやRails、JavaScript関連のことを書いていこうと思います。できれば一日一ポスト、その日に学んだことを書いていきたいです。

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

MephistoでGoogle Analytics使おうと思ってググったら Ruby on Rails Plugin: Google Analytics (blue egg edition) - artweb design というのが出てきたので、早速インストールしてみたんだけど動いていないっぽい。

Mephistoは「rails blog」でググって一番上に出てきたので深く考えもせずにインストールしてしまったんだけど、一年近くバージョンアップされてないし、いまはあんまり活発に開発が行われてるわけじゃないっぽいな。

追記

一晩寝て起きたら動いてた。

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

『RailsによるアジャイルWebアプリケーション開発 第3版』を読んでいます。第10章まで終わったところです。

(Railsに大きく影響を受けている)CakePHPをやったから、Railsをまっさらな状態から学ぶよりも理解は速いだろうと思っていましたが、そうでもない感じです。なかなか苦戦してます。

一言でいうと、RailsはCakePHPとかなり違う。Cakeは Model->Controller->View の流れというか構造がすっきりしてた。例えば posts というテーブルがあれば、Post ModelがあってPostsController があり、ViewにはControllerのメソッドに対応するものがあるという感じです。

しかし『Railsによるアジャイル…』では平気で同名のテーブルをDBに持たないModelやControllerがあったりする。こういうのが混乱します。CakePHPではDB使わないときはわざわざModelに

<?php
class Hoge extends AppModel {
    var $useTable = false;
}
?>

やControllerに

<?php
class HogesController extends AppController {
    var $uses = array();
}
?>

とか書いてあげなきゃいけないのに。

ほかにも基本的にCakePHPではModelのなかでControllerから参照するメソッドを定義したりはしなかったんだけど、Railsではそういうやり方が多い。ModelはDBとのやりとりを定義するためだけの場所ではないっぽいです。逆になんで全部Controllerでメソッドを定義しないのか分からない。率直に言うと気持ち悪かったりします。全部Controllerに書いて、ModelではValidationとかだけやるようにした方がすっきりして見通しが良いと思うんだけどなぁ。

とここまで書いて気がついたんだけど、ModelでもActiveRecordを継承しないやつがあるわけか。よくコードの一行目を読むと、

class Cart

なやつと、

class Order < ActiveRecord::Base

なやつがある。なるほどそういうことだったのか。

こんな感じで前途多難ですが、Railsが出来るっていうとやっぱなんとなくかっこいいので頑張ろうと思います。