Edge Rails

[Edge Rails] 入力文字数の長さを定義する : Custom Length Validation Tokenizer

2008/08/03

validates_length_of では、:minimum, :maximumなどのオプションによって入力最小/最大文字数を定義することができます。いままでは単純に文字数のカウントを行っているだけでしたが、今回追加された :tokenizer オプションによって、文字のカウント方法を定義できるようになりました。

たとえば下記の場合、3行目で入力文字が何ワードあるかを調べるように定義し、10ワード以下であればエラーになるようになっています。

1
2
3
validates_length_of :article, :minimum => 10,
  :too_short => "Your article must be at least %d words in length.",
  :tokenizer => lambda {|str| str.scan(/\w+/) }

Edge Rails, Rails

[Edge Rails] partialのcollection時に好きな変数名をつける:Collection Partial Variable Naming

2008/07/29

# またまた遅れてごめんなさい。。。

今回の機能は、render :partial で :collection を使った場合に好きな変数名を渡せるものです。
恥ずかしながらいままで collection を知らなかったので、自分のためにもそのおさらいから。

render :partial => 'employees', :collection => @workers

Viewで render partial で外部テンプレートをよく呼び出しまが、collectionはその外部テンプレートをループさせるときに利用するものです。
上記の場合、下の _employees.html.erb が @workersの要素(workerひとりひとり)を引き取って、ぐるぐるとまわります。

1
2
名前:<%= woker.name %>
年齢:<%= worker.age %>

collectionは複数形で渡しておくと、テンプレート先で単数形で自動的に引き取るようです。これだと変数名に制約が出てくるので、今回の機能である、:asで変数名を指定することができます。

render :partial => "employees", :collection => @workers, :as => :person

上記のようにすると、workersの要素ひとつひとつがpersonとしてemployeesテンプレートで展開することができます。

今回の機能、というよりも collection を知って嬉しくなりましたが、表示は遅いようですね。。。

ウェブ

iPhone へアドレスブックの内容を整形してインポートする

2008/07/22

iPhoneのような携帯端末で GPS を使ったアプリを作ってみたかったので、テスト端末と自分に言い聞かせて購入に踏み切りました。買ったはいいのですが、アドレスデータの移行がうまいこといかず、ちょっと手を入れたのでメモしておきます。

携帯からアドレスをインポートしたものの、データがうまくない

携帯(MediaSkin)からアドレスのデータをエクスポートしたところ、vcfフォーマットのデータが生成されました。このファイルにはすこし問題があって、

  • 姓名がわかれてなかったり
  • フリガナがついてなかったり

します。

実際、姓名はMediaSkinに分けて入れるフィールドがなかったためなのですが、フリガナについては入っているものの、インポート先のアドレスブック(Mac)で認識できませんでした。

手順

手順というほどのことではないのですが、移行は下記の手順で行いました。通常ならば3. は必要ないのかもしれませんが、今回「姓名を分ける」「フリガナをつける」に対応するため、スクリプトを書いています。

  1. 既存の携帯から miniSD や USBケーブルなどでデータを引き抜く
  2. 抜いた.vcfファイルを UTF-16 に変換
  3. 自作スクリプトで姓名を分割+フリガナの追加
  4. アドレスブック(Mac)へインポート
  5. iTunes でシンク

.vcfはよくわからなかったのですが、下のような感じで BEGIN:VCARD ~ END:VCARD までで一行ずつアドレスデータを記述していくようです(ぼくの携帯からはCHARSET=SHIFT_JISという設定が入っていますが、これは必要ありませんでした)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
BEGIN:VCARD
VERSION:3.0
N;CHARSET=SHIFT_JIS:姓 名;;;;
FN;CHARSET=SHIFT_JIS:姓 名
SORT-STRING;CHARSET=SHIFT_JIS:セイメイ
X-PHONETIC-FIRST-NAME:
X-PHONETIC-LAST-NAME:
TEL;TYPE=PREF,CELL:080********
TEL;TYPE=VOICE:03********
EMAIL;TYPE=PREF,CELL:sei_mei@hoge-mobile.com
EMAIL;TYPE=PCS:sei_mei@hoge-pc.com
CLASS:PUBLIC
BDAY:********
X-CONSTELLATION:
REV:
X-REDUCTION:
X-GNO:
X-GN;CHARSET=SHIFT_JIS:グループ設定なし
END:VCARD

姓名をわける

上の3行目「N;CHARSET=SHIFT_JIS:姓 名;;;;」の箇所で指定することが出来ます。このままだと「姓 名」が名字になってしまいますが、下記のように「;」で姓名をわけてあげることで、ちゃんと認識してくれます(CHARSET~は取ってしまっても問題ありません)。
ぼくの場合、携帯の電話帳に登録するときに姓名を半角スペースでわけていたので、わけるのは簡単でした。。

N;姓;名;;;

フリガナを振る

上の6,7行目「X-PHONETIC ~」に指定することでちゃんと認識します。携帯から出力したときにはここの行がなかったため、スクリプトで追加しました。フリガナは5行目から持ってきたかったのですが、どこからが姓で名なのかsplitのしようがないので、登録されている漢字から、Yahoo! の ルビ振りWebサービス を使って登録しました。

X-PHONETIC-FIRST-NAME:めい
X-PHONETIC-LAST-NAME:せい

(ルビ振りAPI は 光一(こういち)を「ぴかいち」と読むなど、あんまりなところもありましたが、自分で書いていくよりよいので、スクリプトでグルグルまわして取得しました。)

これでアドレスブックにすっきりインポートすることができました。

Rails, Ruby

Ruby Enterprise Edition + Passenger2.0 RC1 でRailsを高速化?

2008/06/15

mod_railsで有名なオランダのPhusion社から Ruby Enterprise Edition がリリースされたので、早速Passenger(mod_rails)と組み合わせて試してみました。

Ruby Enterprise Edition は、Rails に最適化されたRubyのようです(An enhanced garbage collector. An improved memory allocator. )。

インストールはいたって簡単で、指定したディレクトリに(gemも)すべて展開されるため、既存のRubyとの併用も可能です。またアンインストールしたければそのディレクトリを削除すればいいだけです。

Ruby Enterprise Edition のインストール

Ruby Enterprise EdtionはPassengerとの組み合わせでメモリ使用量を33%減にできるようですので、ちょっと期待して使ってみました。

1
2
3
4
5
6
7
8
9
10
# wget http://rubyforge.org/frs/download.php/38084/ruby-enterprise-1.8.6-20080507.tar.gz
# tar zxvf ruby-enterprise-1.8.6-20080507.tar.gz
# ./installer
 
......
 
Where would you like to install Ruby Enterprise Edition to?
(All Ruby Enterprise Edition files will be put inside that directory.)
 
[/usr/local/ruby-enterprise/] :インストールするディレクトリを指定

installerを起動すると、どこに設置するのか(line.10)聞かれてインストールが始まります。途中でRailsもインストールされます(すこし時間がかかりました)。

Passenger(mod_rails) 2.0 RC1 のインストール

ここを参考に。

gemでインストール

2.0RC1はpassenger-1.9.0となっているようです。まずはここからダウンロードしておきます。下記のようにさきほどインストールしたRuby Enterprise Editionを利用してgemでインストール。

1
2
# cd /usr/local/ruby-enterprise/
# ./bin/ruby ./bin/gem install passenger-1.9.0.gem

これでRuby Enterprise Editionディレクトリ内にpassengerが配置されます。

Apacheの設定

次にRuby Enterprise Editionディレクトリ内のbin配下にpassenger-install-apache2-moduleというスクリプトを叩きます。

1
2
# cd /usr/local/ruby-enterprise/
# ./bin/passenger-install-apache2-module

ずらずらとメッセージが出てきて、httpd.confへの編集を促されるので、下記をhttpd.confなどに追記します。Ruby Enterprise Editionをインストールしたディレクトリによってパスは変わるので注意してください。また、デフォルトでproductionとして起動しますが、もしdevelopmentで起動したいなら『 RailsEnv development』を追記してください(Configuring Passengerを参照)。

LoadModule passenger_module /usr/local/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-1.9.0/ext/apache2/mod_passenger.so
PassengerRoot /usr/local/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-1.9.0
PassengerRuby /usr/local/ruby-enterprise/bin/ruby

ヴァーチャルホストの設定は下記の通りです。DocumentRootはRailsアプリのpublicディレクトリを指定します。

<VirtualHost *:80>
      ServerName www.yourhost.com
      DocumentRoot /somewhere/public
</VirtualHost>

起動

これで設定は完了なはずです。Apacheを再起動して設定ファイルを反映して、アクセスしてみます。productionだとエラーがわかりづらいので、最初はdevelopmentで起動した方がいいのかもしれません。

ぼくの環境の場合、普段使っているgemに入っているものが、Ruby Enterprise Editionのgemに入っていなかったため、エラーが起きてしまいました。その場合は、こっちのgemで再インストールを行います。

1
2
# cd /usr/local/ruby-enterpriise
# ./bin/ruby ./bin/gem install <パッケージ>

メモリ使用量の比較

scaffoldしてから、ちょっと手を加えた程度の小さいアプリを動かしてみたところ、140Mくらい利用しているみたいです。増井さんの記事 (素Ruby + Passenger 1.x系)とあまり変わらない。。。うーむ、設定を間違えたのでしょうか。。アプリも環境も異なるので、後ほどmongrelなどと比較してみたいと思います。

Edge Rails, Rails

フレキシブルなto_xml

2008/06/10

Rails2.0でscaffoldを行うと、HTMLと同じURL+.xmlでXMLの取得も行えます。リソースひとつだけ取得するのであればこのままでも大丈夫なのですが、たとえばuserとblogが1:nの関係で、userのXMLを取得する時に同時に複数のblogも取得したい場合どのようにすればよいのかわかりませんでした。

to_xmlを使わずテンプレートでがんばろうかなと思っていたところ、1年前のRyan’s Scrapsでまさにそのものな:includeオプションを見つけました。

1
2
3
4
5
6
7
@user = User.find(1)
@out = @user.to_xml(:include => :blogs)
 
respond_to do |format|
    format.html # show.html.erb
    format.xml  { render :xml => @out }
end

scaffold後に↑のようなソースになりますが、2行目でto_xmlのオプションに:includeを付与しておくと、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<user>
  <id type="integer">2</id>
  <login>ホゲ</login>
 
  ~ 中略 ~
 
  <blogs type="array">
    <blog>
      <created-at type="datetime">2008-06-10T15:06:14+09:00</created-at>
      <id type="integer">1</id>
      <user-id type="integer">2</user-id>
      <title>ホゲブログ1</title>
      <updated-at type="datetime">2008-06-10T15:06:14+09:00</updated-at>
    </blog>
    <blog>
      <created-at type="datetime">2008-06-10T15:36:23+09:00</created-at>
      <id type="integer">5</id>
      <user-id type="integer">2</user-id>
      <title>ホゲブログ2</title>
      <updated-at type="datetime">2008-06-10T15:36:23+09:00</updated-at>
    </blog>
  <blogs/>
</user>

のように、userの子要素として blogs > blog が追加されました。

そのほか to_xml には :include 以外にも便利なオプションがあります。

たとえば不必要な項目を除外する:except、指定項目だけを表示する:only。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
user = User.find(1)
 
user.to_xml(:except => [:id, :created_at])
#=>
# <user>
#   <name>Ryan</name>
#   <email>ryan@spamme.com</email>
# </user>
 
user.to_xml(:only => [:email])
#=>
# <user>
#   <email>ryan@spamme.com</email>
# </user>

また、下記のようにXMLにエレメントを追加することもできます。この例ではidとcreated_atを除外して、serialize_versionを1.1として追加しています。

1
2
3
4
5
6
7
8
9
user.to_xml(:except => [:id, :created_at]) do |xml|
  xml.serialize_version 1.1
end
#=>
# <user>
#   <name>Ryan</name>
#   <email>ryan@spamme.com</email>
#   <serialize_version>1.1</serialize_version>
# </user>

あー便利だなあ。



« Previous Entries » Next Entries