Techracho

Rails 2.3では相対パスでの運用にバグあり?

このエントリーをはてなブックマーク Share
2010.05.19    Ruby on Rails, 伊藤   タグ: , , —    tomotaka   

ごぶさたです、伊藤です。

最近では社内のプロジェクトにもポツポツとRailsを採用するプロジェクトが増えてきてRubyistとしては嬉しい限りです。
しかし、最近Rails2.3のアプリケーションをLinuxサーバ上にApache2.2+Mongrel(Cluster)という構成で配置しようとしたところ、
思わぬトラブルに巻き込まれましたので報告です。

今回配置しようとしたrailsアプリケーションは、いろんなコンポーネントが連携するシステムの一部で、ドメイン直下ではなく
http://hogeramogera/honyarara というような感じでURLのドメイン直下ではなく、相対パスが与えられた上での運用ということになっていました。
Mongrel Clusterでは、このような場合mongrel_cluster.xmlにprefix: /honyararaと書いたり、コマンドラインによる起動であれば–prefx /honyararaとします。
しかし、rails2.3になってからこれがうまく動かなくなってしまったようで、mongrelが出力するログには以下のようなメッセージが残っていました。

** Mounting Rails at /honyarara…
/var/lib/gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:440:in `load_missing_constant’: uninitialized constant ActionController::AbstractRequest (NameError)
from /var/lib/gems/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:80:in `const_missing’
from /var/lib/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/rails.rb:151:in `rails’
from /usr/bin/mongrel_rails:115:in `cloaker_’
from /var/lib/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/configurator.rb:149:in `call’
from /var/lib/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/configurator.rb:149:in `listener’
from /usr/bin/mongrel_rails:101:in `cloaker_’
from /var/lib/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/configurator.rb:50:in `call’
from /var/lib/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/configurator.rb:50:in `initialize’
from /usr/bin/mongrel_rails:86:in `new’
from /usr/bin/mongrel_rails:86:in `run’
from /var/lib/gems/1.8/gems/mongrel-1.1.5/lib/mongrel/command.rb:212:in `run’
from /usr/bin/mongrel_rails:283

普通に例外が起きています!
設定がおかしいとかではなく、これはもうバグのレベルですね。
Railsプロジェクトはリリースエンジニアリングが割としっかりしているように思っていたのですが、そうでもないのでしょうか^^;
missingになっている定数(Rubyではクラスも宣言すると定数扱い)ActionController::AbstractRequestは2.3からなくなったクラスのようでした…

なにはともあれ、問題を解決しないことは仕事が進まないので、いろいろ対処法を探していたのですが、最初に目についた
Rails2.3.2でmongrel_clusterにprefixを付けると起動しない問題の対策を試してみましたが、こちらのページでも述べられているようにpublic以下のコンテンツに対するURL生成が相対パスを考慮しておらず、静的コンテンツのコピーやシンボリックリンクによる対応はあまりにもダサいので、他にいい方法はないかもう少し探すことにしました。

そこで、サブディレクトリ下で Rails 2.3 を動かすときの注意点を参考に、試してみたところ、うまくいきました!
blogによるプログラミング技術やノウハウの共有は本当に素晴らしいですね。
BPSも本ブログを通じて皆様の役立つ技術やノウハウを共有できるように頑張ります!

Macbook Pro 2010 レビューとiPhoto/iTunes移行Tips

このエントリーをはてなブックマーク Share
2010.04.26    Mac, 伊藤   タグ: , , , —    tomotaka   

伊藤です。

木曜日にMacbook Proが届いていたのですが、レビューが遅れてしまいました。

とりあえず、今回購入したMacbook Pro 15インチのスペックを晒します。

- CPU: Core i7 2.66GHz
- メモリ: 4GB 1066MHz DDR3 SDRAM
- ハードディスク: 500GB Serial ATA Drive @ 7200 rpm
- ディスプレイ : 非光沢(ノングレア) 高解像度パネル(1680×1050)
- キーボードJIS

外観の写真なんぞも晒してみます。
個人的にはMagsafeコネクタが新しくなっていたのが気になったので、その部分もクローズアップで写してみました。
このタイプは刺しにくいと思うのですが… どうなんでしょう? 左側にギリギリまで寄せやすくはなりますけどね。

今回大きな変更があったCPUですが、結論からいいますとパフォーマンスは抜群です!
簡単な数値演算プログラムをJavaとRubyで書いて家のコンピュータ(Core 2 Duo E8600 3.16GHz, メモリ2GB)と競争させてみましたが圧倒的にMacbook Proの方が速かったです。
だいたい1.5倍は安定して性能的なアドバンテージが確認できました。これはスゴイ…
※簡単な整数演算のみのベンチマークですのであらゆる状況でCore 2 Duo E8600の1.5倍の性能が出ることを保証するものではありません^^;

タイトルにあるiPhotoとiTunesですが、古いMacから移行してくるには、以下のような手段で行うとメチャ簡単でした。

1. 新旧2台のMacを同じネットワークに接続し、IPアドレスを調べる(ターミナルでifconfigしたり, pingで確認したり)
2. 古いmacのファイル共有をシステム環境設定で有効にする
3. 新しいmacからFinderのサーバへ接続でafp://古いmacで使ってたユーザ名@古いマックのIP/ で接続する
4. iTunesを移行するには: ターミナルで rsync -avz /Volume/古いmacのマウント場所/Users/tomotaka/Music/iTunes\ Music/ ~/Music/iTunes\ Music/
5. iPhotoを移行するには: rsync -avz /Volume/古いmacのマウント場所/Users/tomotaka/Pictures/iPhoto/
~/Pictures/iPhoto/

ちょっとうろ覚えなのでパスとかはフィーリングで修正してください!

ちなみにこれでiTunesを移行すると、連絡先(アドレスブック)もエクスポート→インポートしておけばiPhoneに気づかれず’(?)にマシンだけを変えた感じにできます。(新たに初期化が必要ない)
アドレスブックのエクスポートデータにはiPhoneで設定した写真も登録されていて、よくでてきるなと思いました。

Eclipseのショートカット

このエントリーをはてなブックマーク Share
2010.04.23    Eclipse, 伊藤, 芝原, 馬場      shibachan   

先ほど、同僚とEclipseのショートカットについて情報を共有する機会がありました。

今まで知らなかった便利なものがたくさんあって非常にためになったので、そのうちのいくつかを紹介したいと思います。

タブ操作系

  • Ctrl+W: いま開いているタブを閉じる
  • Ctrl+E: タブ一覧を出す。カーソルがこのメニューに移るので矢印キー + Enterでタブを自由に移動できる
  • Ctrl+PageDown: ひとつ右のタブをアクティブにする
  • Ctrl+PageUp: ひとつ左のタブをアクティブにする
  • Ctrl+F6: タブ一覧を出す。Ctrl+Eと似ている。

ファイル操作系

  • Ctrl + Shift +R: 指定したファイルを開く
  • Shift +Alt + N: 新規プロジェクト、ファイルなど

検索系

  • Ctrl+F: いま編集してるファイル内を検索/置換するダイアログ
  • Ctrl+H: たくさんのファイルを横断的に検索するダイアログ

編集系

  • Ctrl + Space : 補完(Content Assist)
  • Ctrl + / or Ctrl + Shift + C: 複数行を一気にインラインコメントアウト (Java, PHP, Rubyなど)
  • Ctrl + Tab: 複数行を一気にタブ
  • Ctrl + Shift + F: (Java専用?) インデントをフォーマットに従って正しくなおす
  • Ctrl + Shift + O: (Java専用) Organize Imports (使ってないやつを消すとか)
  • Shift + Alt + R: リファクター

Mac用

  • Command + , : 環境設定
  • Emacsキーバインドモード
    • Ctrl + A: 行頭
    • Ctrl + E: 行末
    • Ctrl + F: 1文字右へ
    • Ctrl + B: 1文字左へ
    • Ctrl + P: 1行上へ
    • Ctrl + N: 1行上へ
    • Ctrl + K: カーソルから行末までカット

拡張(設定しておくと便利なもの)

  • SVN コミット (Alt + C)
  • SVN 更新 (Alt + U)
  • SVN ヒストリーを表示 (Alt + H)

Macbook Pro 2010 Early 15inch を注文しました!

このエントリーをはてなブックマーク Share
2010.04.14    Mac, 伊藤   タグ: , —    tomotaka   

伊藤です。

昨晩ついに、一部では噂になっていたMacbook Proの新製品がApple Storeで発売になりました。
長いCore 2 Duoの時代が終わり、ついにMacbook ProにもCore i5/i7が搭載されました!
ずっと新しいバージョンを狙っていたので、昨日勢いのまま、15インチ Core i7モデルを注文してしまいました。

カスタマイズ内容としては、主要部品ではHDDを7200回転のものに、モニタをアンチグレア(光沢なし)のものに変更しました。アンチグレアのパネルは高解像度(1680×1050)のものしか選べないようでした。

届きましたら、またレビュー記事を書きたいと思います。
レビューして欲しい点などありましたら、コメントやトラックバックを頂ければと思います!

Monitで自作デーモンの監視

このエントリーをはてなブックマーク Share
2010.04.05    Linux, 伊藤      tomotaka   

おひさしぶりです、伊藤です。

今日はプロセス監視ツールMonitで、自作のデーモンプログラムの死活監視と、死んじゃったら(+おかしくなったら)再起動してもらうという仕組みを構築する方法をご紹介したいと思います。

まず、自作プログラムですが、どこか適当なところに自分のプロセスIDを記録するファイル(pidファイル)を作ってもらう必要があります。今回作業したマシンはUbuntu Linuxでしたので、/var/run/hoge.pidのような感じで、プロセスIDを格納しただけのファイルを置いておきます。

Monitくんは、このファイルの場所を教えておき、このファイルに記録されているIDのプロセスが死んでいたり、メモリを以上に消費していたり、CPUを100%使っていたり、といった条件で再起動を行わせるよう設定できる便利ソフトです。

Ubuntu Linuxにはパッケージ管理システムaptがあるので、以下のようにしてインストールできます。

$ sudo aptitude install monit

設定ファイルは/etc/monit/monitrcになります。以下のように書き換え+書いてやればokです。

# 最初の方の基本設定を書き換え
set daemon 120 # 120秒ごとに監視
set alert tomotaka@bpsinc.jp # アラートメールが飛ぶあて先

# (snip)

# 自分のデーモンの監視設定を追加
check process hogehoge
    with pidfile "/var/run/hoge.pid"
    start program = "/home/bps/bin/hoge.sh start"
    stop program = "/home/bps/bin/hoge.sh stop"
    if 2 restarts within 3 cycles then timeout
    if totalmem > 100 Mb then alert
    if cpu usage > 95% for 3 cycles then restart

それぞれの意味はなんとなくわかる通りです。起動コマンドはstart program, 停止コマンドはstop programで指定して、メモリを100MB以上消費していたらアラートを投げるなどといった細かい条件を設定できます。より細かい設定項目についてはMonitプロジェクトのドキュメントを見てみてください。
TCPによる接続がダメだったら、とかファイルのMD5チェックサムが変わっていたら、パーミッション、inode、タイムスタンプが変わっていたら、などさまざまな条件設定が可能です。
URLのチェックや、SIP、pingのチェックなども条件に設定できます。これはすごい。

とりあえず、自分のデーモンを監視させたいだけでしたらmonitrcにデフォルトで入っている他のデーモン監視設定は全部コメントアウトして、慣れてきたら少しずつコメントアウトをはずしていくのがオススメです。

設定が終わったらmonitを起動してあげましょう。

$ sudo /etc/init.d/monit start

自分のデーモンが死んでしまったら、ちゃんとmonitによって、再起動されるかどうか? psで自分が走らせているプロセスを見つけてkillコマンドで殺すと、うまくいっていれば、次にmonitがプロセスをチェックしたタイミングでアラートメールでmonitが再起動した旨を伝えてくれるはずです。

Apacheなどをmonitで監視するという例はよく見かけましたが、自分で作ったデーモンをmonitで監視させるという記事があまり(とくに日本語では)見つかりませんでしたので書いてみました。
デーモンのように、落としてはいけないプログラムを自分ひとりでApacheやMySQLなどのたくさんの人がブラッシュアップしているクオリティに持っていくことは難しいです。
デーモンプログラムにもきちんと例外補足やロギングの仕組みを入れておけば、デバッグもしやすく、落ちにくいプログラムにしていくことが可能ですが、個人で実験できる量というのは24時間365日連続稼動時にアプリケーションが遭遇する無限の可能性の前では、残念ながら十分とは言えないでしょう。またテストのしすぎも費用対効果がよくない場合が多いかと思います。
それでも随時処理を行いたい場合には常駐型のプログラムを作成する必要があるわけで、そんな僕らこそ、Monitを使って可用性を確保するべきではないでしょうか。

Ruby on Railsでコントローラでヘルパーメソッドを呼ぶ

このエントリーをはてなブックマーク Share
2009.03.03    Ruby, Ruby on Rails, Web, フレームワーク, 伊藤   タグ: , —    tomotaka   
# app/controllers/application.rb
ApplicationController < ActionController::Base
  class HelperImpl
    include ::Singleton
    include ::ApplicationHelper
  end

  protected

  def helper
    return HelperImpl.instance
  end
end

これでコントローラからApplicationHelperに定義されてるメソッドをhelperメソッド経由で呼べる。

CakePHPのfind, findAll, findCount, delete, deleteAll

このエントリーをはてなブックマーク Share
2009.01.21    CakePHP, PHP, 伊藤   タグ: , , —    tomotaka   

追記: 馬場が記事にしてくれたCakePHP findの形式も非常に参考になります!

伊藤です。

開発ブログには初投稿です。
よろしくお願いします。

今回は最近話題のCakePHPでモデル(データベーステーブル)からデータを取り出したり、カウントしたりするためのfind, およびfindCountの使い方をまとめてみたいと思います。
そんなの本でもWebにでもどこでも載ってるよ!と言われるかもしれませんが、実際に使ってみて1.1に沿ったの内容の解説が多かったり、内容が不正確であったりと困惑したためCakePHP1.2で実際に動くコードということで改めてまとめてみたいと思います。
また、データを削除する際に便利なdeleteやdeleteAllについても触れてみます。
本稿で想定しているCakePHPのバージョンは1.2です。
最近1.2の安定版も出ましたので、これからCakePHPの開発というと1.2が主流になってくるのではないかと思います。

findおよびfindAll
データベースからデータを取得するにはモデルオブジェクトのfindメソッドやfindAllメソッドを使うのがCakePHPの一般的なやり方です。
findAllは以下のようにして使います。タイプ数が少なくて便利なのですが、今後find(”all”, …)形式の呼び出しに統一されやがてfindAllという名前のメソッドはなくなる予定だそうです。

findAllの使い方:

// 取得するフィールドや取り出す並び順が決まっている場合
function someaction() {
    $condition = array("hoge" => 1);
    $fields = array("id", "hoge", "hogege", "moge", "mogege");
    $order = "moge";
    $records = $this->Model->findAll($condition, $fields, $order);
}

// 並び順デフォルト、取得するフィールド全ての場合
function someaction2() {
    $condition = array("hoge" => 1);
    $records = $this->Model->findAll($condition);
}

findで条件に合致する最初の1件のレコードを取得する:

// 取得するフィールドや取り出す並び順が決まっている場合
function someaction() {
    $condition = array("hoge" => 1);
    $fields = array("id", "hoge", "hogege", "moge", "mogege");
    $order = "moge";
    $record = $this->Model->find(
        "first",
        array("conditions" => $condition, "fields" => $fields, "order" => $order)
    );
}

// 並び順デフォルト、取得するフィールド全ての場合
function someaction2() {
	$condition = array("hoge" => 1);
	$record = $this->Model->find("first", array("conditions" => $condition));

	// $record= $this->Model->findByHoge(1);
	// という書き方もできます
}

findで条件に合致する全てのレコードを取得する:

// 取得するフィールドや取り出す並び順が決まっている場合
function someaction() {
    $condition = array("hoge" => 1);
    $fields = array("id", "hoge", "hogege", "moge", "mogege");
    $order = "moge";
    $records = $this->Model->find(
        "all",
        array("conditions" => $condition, "field" => $fields, "order" => $order)
    );
}

// 並び順デフォルト、取得するフィールド全ての場合
function someaction2() {
	$condition = array("hoge" => 1);
	$records = $this->Model->find("all", array("conditions" => $condition));
}

findByIdでフィールド’idが特定の値の1件のレコードを取得する:

function someaction() {
	$record = $this->Model->findById(1); // idが1のレコードを取り出す
}

帰ってくるデータ:

// findAllやfind("all", ...)で帰ってくる形式(複数レコード)
array(
	[0] => array(
		"ModelName" => array(
			"field1" => "value1",
			"field2" => "value2"
		)
	),
	[1] => array(
		"ModelName" => array(
			"field1" => "value1",
			"field2" => "value2"
		)
	),
	...
)

// findByXxxやfind("first", ...)で帰ってくる形式(単一レコード
array(
	"ModelName" => array(
		"field1" => "value1",
		"field2" => "value2"
	)
)

findCountで条件にマッチする行数を数える:

function someaction() {
	$condition = array("year" => 2009);
	$count = $this->Model->findCount($condition);
	// array("conditions" => $conditition)のような形式のオプション配列ではない,
	// findAllに与えるようなarray("field" => "value")形式の配列でよい
}

findAllやfind(”all”, …)で取り出してcount()してもいいのですが、マッチする件数が多い場合はメモリを食いつぶしてしまいますので、
RDBMSに数えてもらうようにするのがスマートな実装でしょう。

deleteメソッドやdeleteAllメソッドでレコードを削除する

// deleteメソッド: 単一のレコードをIDで指定して削除
function someaction() {
	$deleteTargetID = 1;
	if ($this->Model->delete($deleteTargetID)) {
		// 成功
	} else {
		// 失敗
	}
}

// deleteAllメソッド: 条件にマッチする複数のレコードを一括して削除する
function someaction2() {
	$deleteCondition = array("year" => 2009);
	if ($this->Model->deleteAll($deleteCondition)) {
		// 成功
	} else {
		// 失敗
	}
}

deleteメソッドもdeleteAllメソッドも成功すると真を返します。
ちなみにdeleteAllにarray(”conditions” => $condition)のようなfindのオプション形式の配列を渡すと必ず真が帰ってくるので気を付けましょう!

CakePHPはまだ日本語のドキュメントも不十分でWeb上にも1.1と1.2の情報が完全に整理されないまま混在しているため、
開発も手探り感が強いですが基礎の部分をしっかり理解して使いこなせば役に立つツールのひとつだと思います。
今後もCakePHPに関する情報を掲載していきたいと思いますのでよろしくお願いします。
コメントやトラックバックでのツッコミも歓迎致します!

参考:

« 新しい投稿

COPYRIGHT [C] 2009 BEYOND PERSPECTIVE SOLUTIONS LTD. ALL RIGHTS RESERVED.