hocus_pocus
December 21st, 2010
Let me talk about a gem library which casts a spell on your Rails app and enables you to build your Rails app “on the fly” just like editing a Wiki. This is named “hocus_pocus”, and developed as an “isolated engine” for Rails 3.1. The “isolated engine” feature has been developed by Piotr Sarnacki (@drogus) as the RubySOC project #14 and is currently available on Edge Rails. I really appreciate him for creating such a nicely extensible platform and kindly answering all of my questions when we firstly met at RubyConf 2010.
How to use:
1. create a Rails 3.1 app somehow
e.g.)
1
| % rails new hocus_pocus_demo --dev -j jquery |
Note that jQuery is required ATM (this will be improved someday).
2. add a line below to your Gemfile:
1
| gem 'hocus_pocus' |
3. bundle
1
| % bundle |
4. start up your server
1
| % rails s |
that’s all!
Features:
1. request driven generator
You, well grounded Railers, always start your development with URL designing, right? You know, that’s “the Rails Way”.
So, as you decide the URL, just put it in your browser’s URL window.
This engine catches the “routing missing” sort of request, then urges you to input the parameters for the scaffold generator for the “missing” resource.
When the params are submitted, the engine kicks the scaffold generator on the server, and redirects you back to the generated index action.
This is what I meant by “request driven”. This idea is strongly inspired by “Ymir” framework, which has been developed by YOKOTA Takehiko (@i_am_skirnir) in Java language. As I took a look at this, I thought, “hey, even Java can do live code generation through browser. Why can’t Rails do that?”
2. view editor
I guess you’re always frustrated that you have to switch between your text editor and browser again and again while developing web apps.
This engine magically enables you to edit your view file dynamically on your web browser just like a Wiki by clicking the “edit” button on the top right (this is why this product was previously called “wiki_mode” engine).
Of course you can edit the partials as well.

3. url_for missing driven generator
Now, as you edit your view, you probably want to link_to or build a form_for a resource that does not exist yet, because it’s a quite natural way for editing a Wiki.
OK, now you can do it that way. Simply add a link_to like this, and submit the form.
Then another magic happens here. This time, the engine catches “url_for missing” as well, and leads you to the generator again.
4. generating nested resources
As you put a link_to a nested resource like ‘post_comments_path(@post)’,
the engine suggests you to generate a nested resource.
This generates a perfectly working set of code with the following routes.
1 2 3 | resources :posts do resources :comments end |
This is done by another library named nested_scaffold generator.
5. Steak recorder
These days we’re getting familiar with writing end-to-end testing in Ruby code. In the test code, we visit a page, fill_in text fields, select value from drop downs, click buttons, and then assert values in the page body by operating a virtual browser by Ruby.
But, wait. Do you test only by code? Aren’t you doing exactly the same thing by hand anyway? And isn’t it easier and faster to manipulate the browser than writing Ruby code?
So, isn’t it nice if an integration test scenario can automatically be generated while you operate your browser?
This engine records what you did in your browser
and outputs a scenario for Steak.
Comparing to usual generator generated test cases, this scenario might be quite useful and practical since it uses the actual data you entered.
6. Speed
This is not actually a “feature”, but an unignorable benefit of this product. Every time we hit “rails” command or “rake” command on Rails 3, we’re forced to wait several seconds for the Rails process to start up. However, because the generator is directly executed inside the running Rails server process, the hocus_pocus generator runs incredibly fast. When you run the generator from browser, it actually invokes
1 2 | % rails generate scaffold % rake db:migrate |
and usually finishes within a second on my mac.
DEMO:
Finally, to see how it works, here’s my live demonstration video at Sapporo RubyKaigi 03
Though the talk were in japanese, I think you all can get the idea since the main part of the talk were live demo.
I know it’s super buggy ATM (thus still versioned as 0.0.0), needs tons of improvement, but has a great potential to change your development style. The source code is of course available on Github.
Have fun!
This entry is for Ruby Advent Calendar jp-en: 2010 : ATND
The previous post was from takahashim: “Japanese Ruby books in 2010” (thanks for introducing “Head First Rails” at the very top!)
Rails 2.2.2のI18n機能による日本語化がイケてない6つの理由
March 12th, 2009
Rails 2.2から導入されたI18nモジュールだが、さすがにバージョン0.0.1だけあって、実際に日本語でアプリを作ってみると細かいところでちょっとずつイケてなかったりするところが目につく。
以下に、僕が今までに気になったところを挙げてみよう。
1. ARのerror_messages_forでカラム名とメッセージの間に半角スペースが入る
active_record-2.2.2/lib/active_record/validations.rb 208行目より抜粋
1
| full_messages << attr_name + ' ' + message |
半角スペースハードコード!! このおかげで、例えば、「名前」カラムの必須チェックのメッセージが
「名前 を入力してください。」
というように表示されてしまう。半角スペースがめちゃめちゃ気になりますよね。
そこで、こんなチケットをあげて超いいかげんなパッチを投げてみたところ、どうやらそのままコミットされてしまったようだ。
これは、上記でハードコードされた半角スペースをリソースに出しちゃって各ロケールで再定義できるようにしちゃおう、という強引な解決法で、たとえば日本語だったら
1 2 3 4 | activerecord:
errors:
format:
separator: ""
|
な感じで空文字を設定してやると、無事に
「名前を入力してください。」
が出力できるようになる。
どんな言語でも ’ ’ か ” 以外の文字がここに設定されることは無いような気がするので、かなりムダな拡張ではあるのだが、他の部分のキー名との整合性を考えるとこんな感じにならざるを得ないところか。
どなたか他にもっと自然な実装があったら教えてください。Rails 2.3はまだRCだから今なら変更可能かもしれません。
2. Array#to_sentenceで半角スペースが入る
ActiveSupportには、Array#to_sentence という、少なくとも日本語のアプリでは誰も使ってないと思われるマイナー(かつ、Matzいわく、「ブレーキが壊れてる」)な機能がある。
で、Rails I18nプロジェクトでは当然これもローカライズの対象だったわけだが、Rails 2.2.2の実装では、どんなロケールでも
’, ’
でつなぐのは決め打ちで、最後の要素をつなぐフレーズだけandだったりetだったりundだったりできる、というだけ。で、「最後の要素の前に『カンマ』を入れるかどうか」をskip_last_comma ていう値で指定できるようになっていた。
これについては、もうちょっと汎用的にしようよ、ということで、’, ’ の部分も含めてロケールごとに設定できるように変更したパッチを送りつけてみた。
これで、Rails 2.3だと無事にこういうふうになった。
1 2 | >> %w[部屋 Yシャツ 私].to_sentence => "部屋とYシャツと私" |
あんま嬉しくない?
3. 容量の単位のやつで半角スペースが入る
これもマイナーな機能なのでどうせ誰も使ってないだろうし、なんか説明がめんどくさくなってきたから簡単に書くと、以下のような機能があるのだが、
1 2 | >> helper.number_to_human_size 1024 * 1024 * 100 => "100 MB" |
これもRails 2.2.2では数値と単位の間の半角スペースがハードコードされていたのが、こちらの掲示板で「どうよ?」って訊かれたので、「日本人的にはスペース空かないほうが嬉しい」って要望を伝えたら、そのとおりに実装してくれた。
なので、Rails 2.3からは
1 2 | >> helper.number_to_human_size 10000 => "9.8キロバイト" |
とかそんなふうに出力できるようになってます。GJ, Yaroslav!
4. Ruby 1.9に対応してない
Rails 2.2のI18nモジュールはRubyの最新安定版である1.9系では動作しない。
が、このへんのコミットで、Rails 2.3.1ぐらいからやっと Ruby 1.9に対応できたはず。こんにちは、ゆきひろさん!
5. datetime_selectが致命的にダサい
I18n.locale = :ja 状態で Svenのリポジトリ内の日本語リソースファイルを使って date_selectやdatetime_selectを表示してみると、以下のような感じで、致命的にダサくて悲しいコントロールが描画される。

これを解消するにはまぁとりあえず
1
| ja.date.abbr_month_names を [~, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] |
とかにしてやると「月」は出なくなるのだが、これでも数字っぽいドロップダウンが3つとか並んでるだけで、なんのコントロールなんだかよくわからない。やっぱり日本人向けにはドロップダウンの間に「年」とか「月」とかっていう字が入ってるコントロールが欲しいわけだが、これはさすがに日本ローカル過ぎてActionPackに入れてもらうには無理がある。
つまり、今のRailsの標準部品ではどうやっても僕らが望む形のdate_selectは作れないので、日付のヘルパーにはelm200さんのdatetime_helper_jaを使うがよいです。datetime_helper_jaはRails 2.3でもばっちり動作します。
6. YAMLファイルを手で書くのがつらすぎる
i18n_generatorsを使えばいいと思うよ。i18n_generatorsはRails 2.3にも完全対応しています。
./script/generate i18n ja
結論
というわけで結論。
Rails 2.2系で日本語なアプリを作ってる人は、上記のようにI18nがいろいろアレでイマイチなので、とっとと2.3に移行しちゃうがよいと思います。
仙台Ruby会議01
January 30th, 2009
仙台RubyKaigi01に参加した。仙台は、牛タンだけじゃなくて海の幸もすこぶるウマい素敵な街だった。
で、「Rails 2.3(もしくはMerb)で5分で作るトランプゲーム(仮)」というタイトルでLTした。とりあえず資料は以下。
ほんとうはRails 2.3というフレームワークの上で動くネットワーク対戦型トランプゲームフレームワーク、というという題材で、いかに業務ロジックを再利用可能なメタなフレームワーク部分とRubyっぽいDSL(Rails的な意味で)に分けて設計/実装できるか、というのが当初の構想で、いちおうその後の懇親会で見せたとおり、そのためのデモアプリも完成してはいたんだけど、素振りしてみたらこんなのを5分でデモを交えつつ喋るのはぜんぜんムリ、ということがわかったので、急遽方針変更してデモはばっさり落としてしまった。
結局、単に「メタとベタ」というフレーズ(1週間前のRails勉強会の懇親会で福井さんから聞いた)が使いたかっただけなんちゃうか的な感じになっちゃって、ちょっと内容が薄かったかな、と反省。
ちなみに、この問題のスライドだけど、

これは自分で書いたわけじゃなくて、「会社を紹介するスライドをなんかください」って会社の人に言ったらこんなのが出てきた、という。
そんなわけで、もう一度言っとくけど、
どうやらT&Fカンパニーという会社でフェロー(笑)をやってることになってます。
よろしくお願いします。
あと、「トランプゲーム」そのものをえらく楽しみにしててくださった方もいたようで、
『トランプの「ト」の字もでてこなかったじゃないかー』
と、あとで大場nay3にお叱りを受けてしまった。どうもすいません。
いちおう、そっちのほうはもうちょっとコードが整理できたらGitHubに上げとくので、興味がある方は是非ご覧ください。
楽天テクノロジーカンファレンス2008でLTしてきました
December 10th, 2008
2008/11/29に行われた 楽天テクノロジーカンファレンス2008 (updated081216 リンク先更新)内で開催した Rails勉強会@東京第35回 のLT大会で
Rails 2.2のi18nライブラリ、 i18n_generators についてLTしてきた。
自分の資料作りに追われて皆さんの発表がじっくり聞けなかったのはちょっと残念だったかも。
それと、発表がトリだったので、そのまま会場にACアダプタを忘れて帰ってしまったのだが、ちゃんと楽天さんの技術部の中の人が保管してくださっていて、無事に手元に戻ってきた。楽天さんはいい会社です。生ビールも飲めるし。
で、以下LTの資料。Rails 2.2の日本語化とかそこらへんのご興味のある方はご覧ください。というような内容でもないか。
Rails 2.2の I18nによる日本語化を最も簡単に行う方法
November 22nd, 2008
さて、Rails 2.2も 無事にリリース されたわけだが、今回の目玉はなんといっても “I18n” 対応だろう。
つまり、今回の大規模なI18n対応で、やっとこれが
# Rails 2.1.2 より抜粋 options[:object_name] ||= params.first options[:header_message] = "#{pluralize(count, 'error')} prohibited this #{options[:object_name].to_s.gsub('_', ' ')} from being saved" unless options.include?(:header_message) options[:message] ||= 'There were problems with the following fields:' unless options.include?(:message) error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join |
こうなった、と。
# Rails 2.2.2 より抜粋 I18n.with_options :locale => options[:locale], :scope => [:activerecord, :errors, :template] do |locale| (中略) locale.t :header, :count => count, :model => object_name end (後略) |
参考 : 優しいRailsの育て方
そんなわけで、Rails 2.2からは従来のようにRailsのソースをごっそり置き換えたりするモンキーパッチのようなプラグインに頼らなくても、Rails自体の仕組みだけで日本語化(多言語化)が行えるようになった。
◆i18n_generators を使ってみる
さて、それではさっそく日本語化されたアプリを作ってみよう。
このあたり、まだ日本語の情報が全然少ないからよっぽど難しいのかと思われるかもしれないが、実はめちゃめちゃ簡単で、いくつかのコマンドを叩くだけであっさり実現できる。
まずは、何も考えずに、 Rails I18n公式Wikiに載っている 、 i18n_generators という名前の魔法のgemをインストールしておく(名前の最後に “s” がつくのでご注意)。
# http://gems.github.comがgemのSOURCESに入ってない場合は以下を実行してから % sudo gem so -a http://gems.github.com # インストール % sudo gem i amatsuda-i18n_generators Successfully installed amatsuda-i18n_generators-0.2.0 1 gem installed |
それから、Rails 2.2がインストールされている環境で、
% rails -v Rails 2.2.2 |
アプリケーションを作成してcd。
% rails i18n_test
create
create app/controllers
create app/helpers
create app/models
(略)
% cd i18n_test/
|
config/environment.rbを編集してsqlite3を有効に(※ 2.2からデフォルトOFFに変わった?ハマる人続出だと思うんだけど・・・)
じゃあまずはなんかscaffoldでもしてみよう。
以下のようにi18n_scaffoldジェネレーターを使うと、scaffoldがいい感じに他言語化されていたりする。 (081129 updated)
% ./script/generate i18n_scaffold user name:string % rake db:migrate |
日本語のリソースファイルを生成してくれる魔法のコマンドを叩いて(ロケール指定は “ja” で)、
% ./script/generate i18n ja
exists config/locales
create config/locales/ja.yml
create config/locales/models_ja.yml
|
あ、なんかUserモデルにバリデーションでも仕掛けとくか。
app/models/user.rb
class User < ActiveRecord::Base validates_presence_of :name end |
以上!!
サーバーを起動して確認してみると、
% ./script/server |
おおおー、ばっちり日本語化されてるー!!!

ということで、詳しくはあとで書く。
とりあえず、このgem/pluginに関する質問、感想、フィードバックその他は大歓迎です。
あと、 『楽天テクノロジーカンファレンス2008』 というやつで、こいつについて何か話をすることになってるような気がします。
Rails 2.2でroutesの不要なresourcesを消すには
November 22nd, 2008
ブログ再開。
さて、先日Rails 2.2系のmasterに以下の変更がコミットされた。
http://github.com/rails/rails/commit/44a3009ff068bf080de6764a8c884fbf0ceb920e
そもそも今までのRailsの map.resourcesは、なんか routes.rbに1行書くだけで勝手にCRUD+αのroutesがうじゃうじゃ生成されて、邪魔くさいことこの上なかった。実際のアプリだと使われるURLの方が少ないぐらいなのに、rake routesの出力を無駄に汚されて不愉快きわまりない.
というのを、そういえばちょうど前回の Rails勉強会@東京#34 でも懸命に主張してみたりしたのだが、 REST信者 とかいう人たちには「気にするな」とか言われてまったく取り合ってもらえなくて悲しい思いをしたのだった。
しかしみんなにどんなにREST教の教えを説かれても僕にはRailsのこの挙動だけは納得いってなかったんだが、こうなってみるとどうやら僕の感覚の方が正しかったってことですかね。
ということで、以下実例。
- リソースを作ってみたりする
% ./script/generate resource user % ./script/generate resource group |
- rake routesを表示してみたところ。ごにゃごにゃしてて見づらすぎる
% rake routes
groups GET /groups {:controller=>"groups", :action=>"index"}
formatted_groups GET /groups.:format {:controller=>"groups", :action=>"index"}
POST /groups {:controller=>"groups", :action=>"create"}
POST /groups.:format {:controller=>"groups", :action=>"create"}
new_group GET /groups/new {:controller=>"groups", :action=>"new"}
formatted_new_group GET /groups/new.:format {:controller=>"groups", :action=>"new"}
edit_group GET /groups/:id/edit {:controller=>"groups", :action=>"edit"}
formatted_edit_group GET /groups/:id/edit.:format {:controller=>"groups", :action=>"edit"}
group GET /groups/:id {:controller=>"groups", :action=>"show"}
formatted_group GET /groups/:id.:format {:controller=>"groups", :action=>"show"}
PUT /groups/:id {:controller=>"groups", :action=>"update"}
PUT /groups/:id.:format {:controller=>"groups", :action=>"update"}
DELETE /groups/:id {:controller=>"groups", :action=>"destroy"}
DELETE /groups/:id.:format {:controller=>"groups", :action=>"destroy"}
users GET /users {:controller=>"users", :action=>"index"}
formatted_users GET /users.:format {:controller=>"users", :action=>"index"}
POST /users {:controller=>"users", :action=>"create"}
POST /users.:format {:controller=>"users", :action=>"create"}
new_user GET /users/new {:controller=>"users", :action=>"new"}
formatted_new_user GET /users/new.:format {:controller=>"users", :action=>"new"}
edit_user GET /users/:id/edit {:controller=>"users", :action=>"edit"}
formatted_edit_user GET /users/:id/edit.:format {:controller=>"users", :action=>"edit"}
user GET /users/:id {:controller=>"users", :action=>"show"}
formatted_user GET /users/:id.:format {:controller=>"users", :action=>"show"}
PUT /users/:id {:controller=>"users", :action=>"update"}
PUT /users/:id.:format {:controller=>"users", :action=>"update"}
DELETE /users/:id {:controller=>"users", :action=>"destroy"}
DELETE /users/:id.:format {:controller=>"users", :action=>"destroy"}
|
- そこで、routes.rbに以下の条件を追記
% vi config/routes.rb
# 引数は配列でも map.resources :groups, :only => [:show, :index] # シンボル一つでも配列でもOK map.resources :users, :except => :destroy |
- routesがすっきりシンプルになった!
% rake routes
groups GET /groups {:controller=>"groups", :action=>"index"}
formatted_groups GET /groups.:format {:controller=>"groups", :action=>"index"}
group GET /groups/:id {:controller=>"groups", :action=>"show"}
formatted_group GET /groups/:id.:format {:controller=>"groups", :action=>"show"}
users GET /users {:controller=>"users", :action=>"index"}
formatted_users GET /users.:format {:controller=>"users", :action=>"index"}
POST /users {:controller=>"users", :action=>"create"}
POST /users.:format {:controller=>"users", :action=>"create"}
new_user GET /users/new {:controller=>"users", :action=>"new"}
formatted_new_user GET /users/new.:format {:controller=>"users", :action=>"new"}
edit_user GET /users/:id/edit {:controller=>"users", :action=>"edit"}
formatted_edit_user GET /users/:id/edit.:format {:controller=>"users", :action=>"edit"}
user GET /users/:id {:controller=>"users", :action=>"show"}
formatted_user GET /users/:id.:format {:controller=>"users", :action=>"show"}
PUT /users/:id {:controller=>"users", :action=>"update"}
PUT /users/:id.:format {:controller=>"users", :action=>"update"}
|
この機能は、ついさっきリリースされたRails 2.2から有効になっています。
明らかに良くなりましたね、こりゃ。これなら実案件でも使う気になってきた。
第2回Asakusa.rb
August 4th, 2008
7/26(土)、 第2回Asakusa.rbが開催された。
今回は、 隅田川花火大会 の真っ最中に 花火会場のほど近くにお住まいのメンバー のご自宅にて開催、という、とっても夏の浅草「らしい」集いになった。
結局花火に夢中で、肝心のhackの方は全然はかどらなかったわけだが、まぁたまにはそういうのもアリなんじゃないでしょうかね。
そんなわけで、 まとめはこちら 。
今回は、前回よりも一層、「Rubyの凄い人」と「Railsの濃い人」がそれぞれ集まったようなメンバーで、 「RubygemsってやつをRuby 1.9から標準添付にしてるんだけどそんなもの使ったことないよ」っていう人 と 「Rubygemsは毎日使ってるけどRuby 1.9から標準添付になったなんて知らなかった」っていう人 が異文化コミュニケーションを果たすことができたというのは、これもまたAsakusa.rbの活動のひとつの大きな狙いだったりするので、個人的にはけっこう満足だったりする。
それから、今回のもうひとつ大きな収穫と言えば、「Rubyのおかしな挙動を見つけたらどんどん Redmineに上げちゃっていいよ」と Rubyコミッターチームに言っていただけたこと。
そんなわけで、とりあえず前回同様に最新版のRubyでも再現したSEGVの件について Redmineに報告しておいた 。
今回のこれのおかげで、今後の進め方がひとつはっきり見えてきたような気はする。
つまり、日頃いろんな関わり方でRubyを使っている多彩なメンバーが集まって、あちこちからYARVを突っついていじめて、とにかくたくさんバグを出して、片っ端から Redmineに報告する、というだけでも、立派な成果と呼べるものになるんじゃないだろうか?
ただ、それにしてもこのチケットはあまりに大雑把すぎて非常にいただけないので、次からはもうちょっときちんと切り分けができるようになりたい、というあたりは課題かな。
ちなみに、このとき明かされた舞波さんの新しいプラグインの構想が、超life changingで革命的すぎる一品だった!
あれさえあれば、Rails 2.xのあのダサかっこ悪い respond_toブロックがウルトラセクシーな記法に大変身!
心待ちにしておこう。
と思っていたら来た!
http://blog.s21g.com/articles/697
・・・けど、 致命的な問題 が><
ん〜、惜しい!
ファンの皆様、引き続きmaiha先生の新作にご期待ください!
Rails 2.2の I18nについてくわしく
July 27th, 2008
第31回Rails勉強会@東京のセッション「Rails 2.2の I18nについてくわしく」の資料
●I18nモジュールとは
- ある日高橋会長のもとに舞い込んできたメール
- 2008年7月、Rails本体に取り込まれた
- Google groups
- Githubの I18nプロジェクト
- ウォッチしてたら svenfuchsさんからメールが来た!
- バージョンはまだ 0.0.1!
●ソース
github からこんな感じで検索してみる。
http://github.com/rails/rails/search?q=i18n&choice=grep
●重要そうなコミット
●基本機能
I18nというライブラリのクラスメソッドがいくつか提供されている。
>> [I18n.local_methods - Object.methods] => [["append_features", "backend", "backend=", "default_exception_handler", "default_locale", "default_locale=", "exception_handler=", "l", "locale", "locale=", "localize", "normalize_translation_keys", "populate", "store_translations", "t", "translate"]] |
デフォルトの localeは en-USになっている。
>> I18n.locale => "en-US" |
ja-JPに変更してみる。
>> I18n.default_locale = 'ja-JP' |
詳しくはソースで。
●ソースの読みどころ
- I18n gemの本体
activesupport/lib/active_support/vendor/i18n-0.0.1/ 以下 - 基本的な操作とか
activesupport/lib/active_support/vendor/i18n-0.0.1/lib/i18n.rb - vendor/rails/activerecord/lib/active_record/validations.rb
●機能その1. translate
翻訳メソッド。
>> I18n.t 'hoge' => "translation missing: ja-JP, hoge" >> I18n.t 'hoge', :default => 'ほげ' => "ほげ" |
>> I18n.store_translations :'ja-JP', :hoge => 'ホゲ' => {:hoge=>"ホゲ"} >> I18n.t 'hoge' => "ホゲ" >> I18n.t 'hoge', :default => 'ほげ' => "ホゲ" |
●機能その2. localize
日付や時刻、お金のフォーマット
% lv vendor/rails/activesupport/lib/active_support/locale/en-US.rb |
I18n.backend.store_translations :'en-US', { :support => { :array => { :sentence_connector => 'and' } }, :date => { :formats => { :default => "%Y-%m-%d", :short => "%b %d", :long => "%B %d, %Y", }, :day_names => Date::DAYNAMES, :abbr_day_names => Date::ABBR_DAYNAMES, :month_names => Date::MONTHNAMES, :abbr_month_names => Date::ABBR_MONTHNAMES, :order => [:year, :month, :day] }, :time => { :formats => { :default => "%a, %d %b %Y %H:%M:%S %z", :short => "%d %b %H:%M", :long => "%B %d, %Y %H:%M", }, :am => 'am', :pm => 'pm' } } |
●サンプルアプリを作ってみる
- ja-JP.rbという名前のファイルを $RAILS_ROOT/lib/locale/ に配置する。
自分で作るのはめんどくさいので gettext-railsからパチっちゃえ。
たぶんこんな感じで。
% cp vendor/rails/activerecord/lib/active_record/locale/en-US.rb lib/locale/ % cp /opt/local/lib/ruby/gems/1.8/gems/gettext-1.91.0/po/ja/rails.po lib/locale/ % fgrep '%{fn}' rails.po | ruby -e 'puts STDIN.read.gsub("msgid ", "s/").gsub("\nmsgstr ", "/").gsub(/%\{fn\} ?/, "").gsub(/$/, "/")' > trans.sed % sed -f trans.sed en-US.rb | sed s/en-US/ja-JP/ > ja-JP.rb |
- application_controller に以下の filterを設定
before_filter :set_locale def set_locale locale = params[:locale] || 'ja-JP' I18n.locale = locale I18n.populate do require "lib/locale/#{locale}.rb" end end |
- つついて遊んでみる
Rails勉強会@東京30 - what's new in Rails 2.1 セッションまとめ
July 25th, 2008
5月に行われた前回(第30回)Rails勉強会@東京では、ふりかえりの際に 『次回から「前回の勉強会のまとめ」を開催告知Wikiページに載っけるようにしてみよう』という Tryが挙げられていた ので、第30回の時にやった「what’s new in Rails 2.1 セッション」のまとめを。
と言っても、2ヶ月も前のことを今更思い出せるわけないので、以前 GoogleDocsに揚げたやつ をそのまま貼るだけなんだけどね。
なので、以下の内容はあくまでも「2ヶ月前の最新情報」であり、現在の最新情報とは違うかもしれないのでご注意ください(以下こぴぺ)。
what’s new in Rails 2.1 セッション
セッション中に即席で書いてるんでだいぶいい加減な内容です。すみません・・・
■ネタ元
Rails2.1について情報が載ってそうなところあれこれ。
- Ryan’s Scraps
http://ryandaigle.com/tags/Edge%20Rails - redemption in a blog
http://blog.codefront.net/category/ruby-on-rails/ - GitHub
http://github.com/rails - Lighthouse
http://rails.lighthouseapp.com/dashboard - Trac
新しいバグは全て Lighthouseに登録されるようになっているが、
旧バグの中にはまだこちらで生き残っているものもあり。
http://dev.rubyonrails.org/ - Riding Rails
A taste of what’s coming in Rails 2.1
http://weblog.rubyonrails.org/2008/4/1/a-taste-of-what-s-coming-in-rails-2-1
2.1 RC1 リリース告知
http://weblog.rubyonrails.org/2008/4/30/rails-2-1-release-candidate-is-imminent - Ruby on Rails: Core
http://groups.google.co.jp/group/rubyonrails-core - Rails Envy
http://railsenvy.com/ - Railscasts
http://railscasts.com/ - 松田ぽじぺ@Rails東京29
http://docs.google.com/Doc?id=ddn3rmd_11gx4t2cjg - 松田ぽじぺ@Rails東京30
http://docs.google.com/Doc?id=ddn3rmd_12ddzcw4q3
■Rails Edgeを cloneしてみよう
今のところ、Rails 2.1系を触ってみるには、以下のような方法がある。
- RC1を使う
% rake rails:freeze:edge |
zipで固められた最新ソースの玉を落として解凍してくれるように変更されたらしい
(たぶん Gitがまだ充分に普及していないから(?))。
が、zipファイルを上げる運用はまだ運用が開始されていない模様。
- piston
pistonが Gitに対応してくれたらこれが一番ラクかも。
- gitコマンドで
% rails edge_080518 % cd edge_080518/rails % git clone git://github.com/rails/rails.git |
■Rails2.1の新機能たち
主立ったものを列挙してみます。これまた当日に思い出しベースで書いているので網羅はできてない気がしますが。
- named_scope
昨秋登場した has_finder という life changingなプラグインが本家に取り込まれた。
個人的には、おそらくこれが Rails2.1の最大のウリなんじゃないかと(詳しくは後述)。
http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-finder-functionality
http://pivots.pivotallabs.com/users/nick/blog/articles/284-hasfinder-it-s-now-easier-than-ever-to-create-complex-re-usable-sql-queries
- has_one :through
関連テーブルを挟んだ has_one 関連がエレガントに書ける機能。
http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-one-through
- ARのレコードに dirty object機能
save時に発行される update文を、変更されたカラムのみを対象にすることができて、うまく使えばパフォーマンスの向上が見込まれる。
さらに、変更前のオリジナルの値も保持してくれている。
ADO .Netの DataTableにあったようなあの機能という理解で良いかと。
http://ryandaigle.com/articles/2008/3/31/what-s-new-in-edge-rails-dirty-objects
http://dev.rubyonrails.org/changeset/9157
http://blog.codefront.net/2008/04/05/living-on-the-edge-of-rails-14-the-extreme-edition-extremely-late/
http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-partial-updates
- AR#create にブロックを渡せるように
ブロック内部を returning的に書ける文法が追加された。見た目がRubyっぽく書けて嬉しいかも?
http://github.com/rails/rails/commit/dd120ede53eaf71dee76894998a81626b7a689fc
- migrationファイルのファイル名が連番じゃなくてタイムスタンプに
http://ryandaigle.com/articles/2008/4/2/what-s-new-in-edge-rails-utc-based-migration-versioning
- schema_infoテーブル → schema_migrations という新テーブル
- Railsプロジェクトに依存している gemを設定できるように
http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies
- RAILS_ROOT → Rails.root, RAILS_ENV → Rails.env
http://dev.rubyonrails.org/changeset/9180
- ActiveModel
2.1には正式に入るのかも?
- TimeZone機能
rake time:zones:*
|
→ 非US系開発者から若干反感を買ってる模様(以下のコメント欄など参照)。
http://rails.lighthouseapp.com/projects/8994/tickets/195-convenience-methods-for-time-zones-outside-the-u-s
- javascript_include_tag とかの :defaults を自分で再定義できるように
http://blog.codefront.net/2008/03/20/living-on-the-edge-of-rails-12/
- ドキュメントがすごい勢いで充実中
- Ruby1.9 / 1.8.7 対応
実はこれが一番嬉しい変更、という人も多いかも。
1.9系のメソッドたちは ActiveSupportと激しくかぶるので、ActiveSupportにかなり修正が入っている。
- インフラの変化
Subversion → Git
Trac → Github
Trac → Lighthouse
- script/plugin install が Gitのリポジトリに対応
- script/dbconsole
上記のとおり。
http://github.com/rails/rails/commit/4a07103687084496b773e18a03b1f2f5e686f7ad
(※懇親会で喋ってて思い出したので追記)
- ARで connection pool の実装が開始
http://groups.google.co.jp/group/rubyonrails-core/browse_thread/thread/16851dd787844a34/e89e9c741f89227e
■ named_scopeを詳しく
以下、セッション中にデモで書いたコード +α をいちおう載っけておきます。
もう終わった勉強会のぽじぺを見る人って居るんかな?とは思いつつ・・・
- Railsアプリを生成して Edge Railsを取得
手順は上記のとおり。
- こんな感じのいいかげんな modelを一丁 generate
% ./script/generate model person name:string age:integer gender:integer % rake db:migrate |
- サンプルデータを何件か作って、
>> Person.create :name => 'person 1', :age => 20, :gender => 1 >> Person.create do |p| >> p.name = 'person 2' >> p.age = 30 >> p.gender = 2 >> end >> Person.create :name => 'person 3', :age => 3, :gender => 1 |
- named_scopeをあれこれ作ってみる
class Person < ActiveRecord::Base # Hashで conditions。基本形。 named_scope :male, :conditions => {:gender => 1} named_scope :female, :conditions => {:gender => 2} # Stringで conditions。 named_scope :adult, :conditions => 'age >= 20' # Procで scopeを定義した形。例がへぼくてすいません。 named_scope :name_start_with_p, lambda { {:conditions => ["name like ?", 'p%']} } # Proc方式だと scopeに引数も渡せる。 named_scope :older_than, lambda {|n| {:conditions => ['age >= ?', n]} } # さっきのへぼい例もこれなら実用的。 named_scope :name_start_with, lambda {|s| {:conditions => ["name like ?", "#{s}%"]} } end |
- 作ったnamed_scopeたちをつついて遊んでみる
>> Person.male Person Load (0.000603) SELECT * FROM "people" WHERE ("people"."gender" = 1) >> Person.adult Person Load (0.000596) SELECT * FROM "people" WHERE (age >= 20) >> Person.older_than(7) Person Load (0.000651) SELECT * FROM "people" WHERE (age >= 7) |
動いた。あれ?genderは予約語だったか?とか思いつつ。
こんな調子で、ちっちゃいクエリの断片をあらかじめ名前を付けて定義しておくことができる、というのが named_scope の基本機能。
これだけだと、昔 Javaが流行ってた頃に DAO って言われてたやつと何が違うの?と言われてしまいそうなところだが、
- なんと、ネストして呼び出した時のSQLの発行は一回だけ!
>> Person.female.adult Person Load (0.000494) SELECT * FROM "people" WHERE ((age >= 20) AND ("people"."gender" = 2)) |
とにかくこれがすごい。呼び出し側のコードの可読性がめちゃめちゃ高くてシビれる。
→ 流れるようなインターフェース(笑)
- そういえばセッションでは説明し忘れたけど、countとか書いても勝手にネストしてくれるよ。
>> Person.older_than(10).female.name_start_with('松').count SQL (0.000375) SELECT count(*) AS count_all FROM "people" WHERE (((name like '松%') AND ("people"."gender" = 2)) AND (age >= 10)) |
join とか sortとか、その他もろもろは今回は省略。
ちなみに、実はそのあたりは今でも盛んにコミットが行われているところなので、仕様もまだ多少揺れる可能性があるかも。
- named_scopeメソッドで作られるものたちの実体は?
>> pp Person.scopes {:male => #<Proc:0x017ead50@/Users/matsuda/railstokyo/edge080518/vendor/rails/activerecord/lib/active_record/named_scope.rb:87>, :name_start_with => #<Proc:0x017ead50@/Users/matsuda/railstokyo/edge080518/vendor/rails/activerecord/lib/active_record/named_scope.rb:87>, :female => #<Proc:0x017ead50@/Users/matsuda/railstokyo/edge080518/vendor/rails/activerecord/lib/active_record/named_scope.rb:87>, :adult => #<Proc:0x017ead50@/Users/matsuda/railstokyo/edge080518/vendor/rails/activerecord/lib/active_record/named_scope.rb:87>, :name_start_with_p => #<Proc:0x017ead50@/Users/matsuda/railstokyo/edge080518/vendor/rails/activerecord/lib/active_record/named_scope.rb:87>, :scoped => #<Proc:0x017ead50@/Users/matsuda/railstokyo/edge080518/vendor/rails/activerecord/lib/active_record/named_scope.rb:87>, :older_than => #<Proc:0x017ead50@/Users/matsuda/railstokyo/edge080518/vendor/rails/activerecord/lib/active_record/named_scope.rb:87>} |
こんな感じの、キー = 宣言した名前、値 = Proc のインスタンス、な Hash で保持されていることがわかる。
- これを踏まえて、よくある検索画面を想定して動的にクエリを組み立ててみる
さて、この named_scope機能が実際のアプリでどう使えるか、って考えてみると、
よくある検索画面みたいなやつで条件に含める項目自体が動的に変化するようなケースを
思いつくんじゃないだろうか。
つまり、どの scopeをクエリに組み込むか、というのを動的に選んでいきながら複雑なクエリを組み立てて、
最後に一発ドーンと実行するようなイメージ。
def self.search(params) exec_scopes = [] if params[:is_male] exec_scopes << [:male, nil] end if params[:age_min] exec_scopes << [:older_than, params[:age_min]] end # (中略) end |
おまけ
セッションでは上記のように書いて、こんな感じで実行したい scopeを配列とかに溜めて
evalか injectぐらいでガツッと実行してやるしかないよねー、みたいな説明をしておいたが、
Yuumiさんから「かなりぐちゃぐちゃなコードになりそう」
というようなご意見を頂いた。うーん。そうなんですよねー。
さて、そこらへんはその場でコードは書ききっていなかったので、以下参考までに実装イメージを。
※ 実装案1
つまりこういう文字列を組み立てて、
exec_scopes_string = exec_scopes.map {|s| "#{s[0]}(#{s[1]})"}.join('.') |
evalに食わせるという。
引数の型とか数とかまともにハンドリングしてないけどまぁ大体こんな流れで。
eval "Person.#{exec_scopes_string}"
|
※ 実装案2
injectでぐりぐり実行させる。
exec_scopes.inject(Person) {|p, s| scopes[s[0]].call p, *s[1]} |
やっぱりこっちのほうがイケてそうかなぁ。
ということで、案2のほうで実装してみたサンプルがこちら。
引数を複数取る scopeにも対応したかったので、例としてこんな scopeを追加して、
# 複数の引数。 named_scope :age_between, lambda {|from, to| {:conditions => ['age between ? and ?', from, to]} } |
検索を実行するメソッドをこんなふうに。
def self.search(params) exec_scopes = [] # [実行するスコープ, [引数の配列]] な配列 exec_scopes << [Person.scopes[:male], nil] if params[:is_male] exec_scopes << [Person.scopes[:older_than], params[:age_min]] if params[:age_min] exec_scopes << [Person.scopes[:age_between], [params[:age_between][0], params[:age_between][1]]] if params[:age_between] # あとは、こんな調子で他の paramsたちの解釈をずらずらと書く。ここでは省略。 # これが呼び出し部 exec_scopes.reverse.inject(Person) {|p, s| s[0].call p, *s[1]}.all end |
実行結果はこちら。
>> Person.search({:is_male => true, :age_between => [10, 30]}) Person Load (0.000518) SELECT * FROM "people" WHERE (("people"."gender" = 1) AND (age between 10 and 30)) |
ということで、とりあえずめでたく動作。
けっこうスッキリ書けたと思うが、でもこれは確かに書いた本人にしかわからないコードかも・・・
ポイントは便利メソッド injectの()内引数の使いかたと、最後にさりげなく書かれた .all(scopeが1個も使われなかった場合のデフォルトscopeになる)の工夫。
やっぱり Rubyはこんな書き方ができちゃうから面白い。
ただ、このあたりは需要がありそうなので、きっとフレームワークがもうちょっと親切な仕組みを提供してくれることでしょう。
任意のファイル名とディレクトリ名の fixturesが読み込めるようになった
July 24th, 2008
Railsの fixturesはたいへん便利な仕組みなのだが、今までは決められた名前のディレクトリ($RAILS_ROOT/test/fixtures/)内の決められた名前(テーブル名と同じ名前)のファイルしか読み込めないという制約があったため、例えば複数パターンのテストデータを用意しおいて切り替えて DBに食わせたいような場合なんかに、ちょっと不便に感じることがあった。
が、最近の edgeでは2箇所ほど fixtures関連の修正が入っており、fixturesの使い勝手が向上している。
1. サブディレクトリ内の fixturesを読み込む rakeタスク
まず、fixturesをディレクトリで分けて複数用意してディレクトリ名を指定して読み込む rakeタスクが 実装された 。
例えばこんな fixturesファイルを用意して、
test/fixtures/users.yml
john: name: John paul: name: Paul |
ふつうに rakeタスクで loadすると、
$ rake db:fixtures:load |
DBの中身はこうなる。
$ ./script/runner 'p User.all.map(&:name)' ["Paul", "John"] |
と、ここまでは従来どおりだが、さらに Rails 2.2では、こんなディレクトリを用意して、
$ mkdir test/fixtures/ja |
こんな fixturesファイルを作ったら、
test/fixtures/ja/users.yml
taro: name: 太郎 hanako: name: 花子 |
こんなコマンドで loadできるようになった。
$ rake db:fixtures:load FIXTURES_DIR=ja |
結果はこのとおり。
$ ./script/runner 'p User.all.map(&:name)' ["花子", "太郎"] |
2. fixturesメソッドでテーブル名と同じ名前以外の任意のファイルを読み込めるようになった
こちらの件は、折しも RubyKaigi 2008の会場で Rails勉強会@東京ブースのよろず質問コーナーで質問を頂いた内容だったりする。
Rails 2.2では このパッチのコミットのおかげで バッチリ解決できそうになったので、いまさらここで遅レスな回答を。
例えば今度はこんな fixturesファイルを読み込ませたい場合、
test/fixtures/elp.yml
keith: name: Keith greg: name: Greg carl: name: Carl |
テストケースではこんなふうに書けばOKになった。
test/unit/user_test.rb
require 'test_helper' class UserTest < ActiveSupport::TestCase set_fixture_class :elp => User fixtures :elp test 'ELP should be loaded through YAML file' do assert_equal %w[Carl Greg Keith], User.all.map(&:name).sort end end |
しかし、今の Railsのデフォルトでは test/test_helper.rb に
fixtures :all
|
とか書いてあったりするので、fixturesディレクトリ直下にこんなファイルが置いてあると、全てのテストケースでこの ymlファイルを同名のテーブルにロードしに行こうとしてガンガン落ちる。
そこで、上記の1番の例を思い出して、特定のテストケースでのみ使いたいようなテストデータはサブディレクトリに置いとけば良いじゃん、というのがトレンドになりそう。
$ mkdir test/fixtures/users $ mv test/fixtures/elp.yml test/fixtures/users/ |
テストはこんなふうに書けば、
test/unit/user_test.rb
require 'test_helper' class UserTest < ActiveSupport::TestCase set_fixture_class :'users/elp' => User fixtures :'users/elp' test 'ELP should be loaded through YAML file' do assert_equal %w[Carl Greg Keith], User.all.map(&:name).sort end end |
$ rake test:units (中略) 1 tests, 1 assertions, 0 failures, 0 errors |
カンペキ!
ポイントは、ディレクトリ名とファイル名をつなげたものを引用符で囲って書くところでしょうか。
以上、こんな感じで回答になってますでしょうか? > 川端さん
Gitでプラグインをインストールする時にバージョン指定ができるようになった
July 23rd, 2008
昨今の Gitブームを受けて、Rails 2.1 から script/plugin スクリプトが Gitに対応したのは記憶に新しいところ。
だが、このコマンドでは単に Gitリポジトリの最新版を取得してきてしまうため、みんな こんな 疑問を抱えながら使っていたわけだが、実は Gitでタグ付けされた安定版を導入しようと思ったら、script/pluginにはそんなオプションは用意されていなかったので、 こんなふうな 面倒な手順を踏まなければならなかった。
$ cd vendor/plugins $ git clone git://github.com/dchelimsky/rspec.git $ git clone git://github.com/dchelimsky/rspec-rails.git $ cd rspec $ git checkout 1.1.4 $ cd ../rspec-rails $ git checkout 1.1.4 $ cd .. $ rm -rf rspec/.git $ rm -rf rspec-rails/.git $ cd ../../ $ script/generate rspec |
これを解消すべく こんな チケットが挙がっていた、というのは、これまた RubyKaigiの時に書いた これ に書いたとおりだが、その後この dchelimsky案よりもっとエレガントな実装が行われ、 先日コミットされた 。
これによって、結論としては、今の edge Railsでは以下のコマンドで任意のタグがついたバージョンのプラグインをインストールすることができるようになった。
$ ./script/plugin install git://github.com/dchelimsky/rspec.git -r 'tag 1.1.4'
|
しかも、試してみればわかるが、Subversionのころと比べると驚異的に速い!!
これでもはや Railsプラグインが Gitに移行しない理由はひとつもなくなったと言って良いのではないだろうか。
named_scopeがインスタンス生成時にも使えるようになった
July 23rd, 2008
ちょっと前の話だが、 こちらのコミット にて、hashで条件指定された named_scopeを経由してモデルのインスタンス生成を行った場合、その条件の値があらかじめセットされたインスタンスが作られるようになった(この件については、 こちら の「注目の未解決チケットたち」に書いたとおり以前から 要望が挙がっていた もの)。
どういうことかというと、例えばこんな感じ。
こんなようなmodelがあるとして、
class User < ActiveRecord::Base belongs_to :prefecture # 引数を取らない named_scope Prefecture.all.each do |prefecture| named_scope "lives_in_#{prefecture.name.downcase}".to_sym, :conditions => {:prefecture_id => prefecture.id} end # 引数を取る named_scope named_scope :name_is, Proc.new {|name| {:conditions => {:name => name}}} named_scope :aged, Proc.new {|age| {:conditions => {:age => age}}} end |
まずはふつうに検索。
User.lives_in_tokyo.name_is('Matsuda').aged(16) |
発行されるSQL
User Load (0.000373) SELECT * FROM "users" WHERE ((("users"."age" = 16) AND ("users"."name" = 'Matsuda')) AND ("users"."prefecture_id" = 13)) |
ここまでは今までどおり。
これを newとか createとかにつなげるとこうなるッ!
user = User.lives_in_tokyo.name_is('Matsuda').aged(16).create |
実行結果
User Create (0.001407) INSERT INTO "users" ("name", "created_at", "updated_at", "age", "prefecture_id") VALUES('Matsuda', '2008-07-23 18:09:27', '2008-07-23 18:09:27', 16, 13) #=> #<User id: 1, name: "Matsuda", age: 16, prefecture_id: 13, created_at: "2008-07-23 18:09:27", updated_at: "2008-07-23 18:09:27"> |
かっこいー!
第1回Asakusa.rbの成果のご報告
July 17th, 2008
第1回Asakusa.rb のときに発見されて修正された Railsのバグをパッチにして投げてみたところ、
http://rails.lighthouseapp.com/projects/8994/tickets/623
そっこーで無事本体に取り込まれた。
http://github.com/rails/rails/commit/bb33432b0f5bf644713e696e4dafc7e7d3cc5808
ということで、さっそく成果が出たよ!めでたい!
なにしろこんなたった8文字書き加えるだけのパッチでも、僕一人ではどんなに頑張っても絶対に解決できなかったであろう、(僕にとっては)充分に高度な内容である。
そういう意味でも、みんなに集まってもらって会合を開いた価値はあったわけで、非常に喜ばしい。
しかし、エラーメッセージを一目見て解決してくださったのはささださんだし、
正しいデバッグの方法を指南してくださったのはgotoyuzoさんだし、
実際にキーボードを叩いてくださったのはかくたにさんだし1、
それ以前にネットにつなげてくれたのは cojiさんだし、
という具合なので、実は僕は何もやってないんだけど、
でもコミットは何故か僕の名前でクレジットされてて恐縮だ2。
そんな意味を込めてチケットの説明文には “We” って書いたんだけど、
でもなんの文脈もないので、「"We"って誰だよ?」って感じだよな。
そしてこれにて一件落着、かと思いきや、その直後にこんなアップデートが。
http://github.com/rails/rails/commit/3c282f3a0a7c1d5ab91241674251794ead5fa41d
なになに? uses more memory than eval with block ? そうなの?
Rubyは奥が深いなぁ・・・
1 このあたりについては かくたにさん的には何やらいろいろ言いたいことがあったらしい 。すみません><
2 しかも gitの configの user.name あたりの設定ができてなくて漢字でフルネームとかいって、恥ずかしすぎる><
Asakusa.rbが結成されました!
July 14th, 2008
このたび、こんなような趣旨で、 Asakusa.rb という団体を発足させてみた。
第1回 Asakusa.rb のご案内 – http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/45213
メールの内容を再掲するのもなんなので趣旨を3行でまとめると、
- 東京の下町とかそのあたりに住んでいる Ruby技術者たちが、
- オフで集まって酒でも飲みながらみんなで楽しくハックしつつ、
- 何か具体的な「成果を出す」活動を目的とした地域Rubyistコミュニティ
である。
なんだか偉そうなことを言ってるが、もちろんいきなり僕一人でそんなことができるわけがない。
今回の件は、ちょっとしたご縁があって、ささだ大先生・かくたに大明神のお2人の強力なお力添えがあってのことである。
もともとの話の発端は RubyKaigi 2008の「3日目」にさかのぼるのだが、まぁつまり、ここらへんで張られた伏線がやっと回収されてきたというところだろうか。
http://kakutani.com/20080623.html#p01
さて、そんなわけで、さっそく第1回の会合を7/11の金曜日に実施した。
MLへの告知がほんとに直前になってしまったことについては、何人かの方から「急すぎ」というもっともなご指摘をいただいた。
最初からあんまり人数ばっかり集め過ぎて収集つかなくなっちゃうのも嫌だから、第1回は敢えてある程度敷居を上げてコアなメンバーに絞ろうとしたという意図も多少あったのだが、その反面えらくクローズドな印象で感じ悪い告知になってしまった。
うーん・・・。難しい。
まぁそれでもけっこう人は集まってくれるもんで、当日は、
ささださん
かくたにさん
後藤裕蔵さん
Cojiさん
レオさん
「バリケン」の人
などなど、Yet Another Ruby Cityの名に恥じない総勢10名の実に豪華すぎるドリームチームが集結することになった。
肝心のハックの方は、こちらの準備の不手際もあってなかなかネットに繋がらなかったり、と、しょっぱなからずいぶんとグダグダな展開になってしまったが、それでも結果としてはあの短時間にしては充分な「成果」は出たと思うし( Railsの YARV対応漏れバグを1箇所直した!! )、なにより、この人たちが集まると何かめちゃめちゃものすごい化学反応が起こってすげぇことができちゃいそうな手応えを感じた。
そんな中に居合わせることができただけでも、日常では味わえない素晴らしくエキサイティングな体験だったと思う。
この歳になって自分がバンドで一番下手くそなメンバーで居られるというような、そんな素敵な機会を与えてくださった皆様に心から感謝したい。
そんなわけで、よければ引き続きこれからも活動を続けて行きたいと思っておりますので、
みなさま、今後とも Asakusa.rb をどうぞよろしくお願いいたします。
それから、これを読んで興味を持たれた方は、 http://qwik.jp/asakusarb/ に書いてある手順でメール1通でご加入いただけるので、次の機会には是非是非ご参加ください!
お待ちしております。
Hash key in :conditions
July 2nd, 2008
昨日の 一件のコミット で、今まで ActiveRecordで不満に思ってたところがまた一つ解消された。
User.all :joins => :items, :conditions => {:age => 10, :items => {:color => 'black' }} |
今まで AR#findのパラメータって、:joins とか :includes はなんぼでもテーブルを多段にネストして書けてたのに1、
:conditions では何故か Hashで書けるのは自テーブル内のカラムまでだった。
つまり、今までは、
Item.all :conditions => {:color => 'black'} |
だったら完全に Rubyの Hashの世界でキレイに書けるくせに、
ってことは、
SELECT "users".* FROM "users" INNER JOIN "items" ON items.user_id = users.id WHERE (items.color = 'black') |
を発行したかったら当然こうだよね、
User.all :joins => :items, :conditions => {:items => {:color => 'black'}} |
と書いてみたらダメで、この場合
User.all :joins => :items, :conditions => ['items.color = ?', 'black'] |
とか書かなきゃいけなかった。
ところが今回のパッチのおかげでごくふつうにこんなふうに
User.all :joins => :items, :conditions => {:items => {:color => 'black'}} |
なんでも Hashで書けるようになった、と。
めでたしめでたし。
Rails 2.1.1 も順当に良い改良がどんどん入ってて嬉しいですね。
1 参考: Cascaded Eager Loading が欲しい@くまくまー , Cascaded Eager Loading@くまくまー




