第4回Rails勉強会@東京

昨日3/19は第4回となるRails勉強会に参加してきました。前回欠席してしまったこともあり、今回ははじめてお会いする方、久々にお会いする方がたくさんいらして新鮮な感じでした。

今回のエントリは以下の構成です。

  • 前半RJS話
  • 後半Rails1.1の新機能、予習したのはcalculationプラグイン
  • 私的KPT

前半セッション:RJSテンプレートについて

何も準備せずに望んでしまったセッションです。おかげでぐだぐだになってしまい、参加してくださった方には申し訳なかったかも。

進め方は基本的にくまくまーさんのRJSテンプレートの記事*1を読みながら試してみるという感じでした。

いちおう試してみて、もっとも簡単なサンプルのみ動くようになりました。以下の感じで動かしてみることができるようになるかと。

  • link_to_remote でxhrを発行するリンクを作成。
  • 上記でしてしたアクションに対応するRJSファイルを用意。
  • RJSファイルにいろいろとアクションを書く。page.xxxでprototype.jsで定義されているメソッドに類似のメソッドなどを呼び出せる。

これで、Javascriptを一行も書かずに、既存のサンプルプロジェクトへJavascriptなこうかを追加できました。もうちょっと深く探りたかったんですが、それは次回でのリベンジ待ちということで。すみませぬ。

後半セッション:Rails1.1の新機能

増井さんが訳してくださった記事をみんなで読みました。

私がちゃんと追っていた&ちょっと突っ込んで紹介できたのは2点ほど。

Symbol#to_proc

なかなか使いどころがピンとこない拡張ですが、Symbol#to_procメソッドが追加されていました。ありそうな使いかたの一つ目は各所で言及されているような単純なブロックの代用として、一時変数なんかを省略して書けるようになる、というところ。

 [1, 2, 3, 4].map(&:to_s)
   # => ["1","2","3","4"]

これはようするに

 [1, 2, 3, 4].map{|obj| obj.send(:to_s) }

と同じ動きですね。

で、もうひとつ面白い使いかたとして、例えばARのオブジェクトなんかをロードするとき、単純にそのカラムを取り出したいときと、そのカラムの内容を加工して取り出したいときに、受け側を簡単に作れるようになります。

  def greet(ar_obj, process_obj_name)
    return "ようこそ、#{process_obj_name.to_proc.call(ar_obj)}"
  end

と定義しておきますと、

 me.name   # => もろはし
 me.count  # => 3

のときに

 greet(me, :name)
   # => ようこそ、もろはし

 greet(me, Proc.new{|obj| "#{obj.name} さん。#{obj.count}回目のお越しですね。" }
   # => ようこそ、もろはしさん。3回目の起こしですね。

みたいな感じで使えます。Capistrano(かぴすとらーの)の定義なんかでは、SymbolまたはProcでパラメータを指定する、なんてことが結構あるようですので、それを簡潔にするための追加なのかなぁ、と。

calculation

これまではAR::Base#find()でロードしたあとにEnumerable#inject()なんかでループさせていた集計機能が、SQL側での集計関数呼び出しでできるようになりましたよ、という拡張。

特筆すべきは一対多の関連がある場合に子の側のテーブルに対してcalculationした場合の動作。なにもしなくても、親側のインスタンスがロードされてキーに、集計結果が値になったOrderdHashで値が返ります。

すなわち

DB:
-- prefectures --
 id| name   |population|area_id|
 1 | 北海道 | 564      | 1
 2 | 青森県 | 145      | 2
 3 | 岩手県 | 139      | 2
 4 | 宮城県 | 237      | 2
 
-- areas --
 id| name
 1 | 北海道
 2 | 東北

Ruby:
 class Prefecture < ActiveRecord::Base
   belongs_to :area
 end

だった場合に、Prefectureに対して集計を行うと

 Prefecture.sum(:population, :group => :area)
   # => (Areaオブジェクト@北海道) => 564,
        (Areaオブジェクト@東北)   => (145 + 139 + 237 + ..)

という結果が返ってきます。実際に発行されるSQLはJOINは使用せず、GROUP BY area_idで集計したあと、SELECT * FROM Areas WHERE id IN (1, 2 ...)として取得し、内部でループを回しています。また、その作りとなっているため、2段階以上のgroup化*2はまだできない模様です。

それでもこれまではRuby側で処理しなきゃいけなかった計数が簡単に、そして高速にできるようになるというのはうれしいもの。この調子でSQLをいかすメソッドが増えていき、近い将来夜間バッチもRubyで、という流れにならないかなぁ、ならないか。

ちなみにここでサンプルとして使った都道府県毎の人口DBをこちらにアップロードしておきました。Railsで遊びたいんだけどサンプルDBがない、とか、本番データをテスト用に使うのは一としてどうよ、という方がいれば、御利用ください。

私的KPT

Keep
  • セッションを積極的に立てたり、しゃべったりするのはよいことだと思う。
  • 怖じ気づかずにいろんなひととと積極的に話す。今後も続ける。
Problem
  • 準備せずにぐだぐだのセッションオーナーになってしまうのは考え物。
  • 「私も勉強したい」系ならそれはそれでよいんだけど、その場合もちゃんと聞きたいことをまとめといたほうが有意義な時間になる。
  • サンプルRailsアプリとか動作環境とかを整える必要あり。プロジェクタに写すためのターミナルが必要。
Try
  • WEBRickはソースがきれいとのこと。ちゃんと読む。
  • 次回勉強会にてRJSリベンジするため勉強しておく。
  • ActiveSupportの黒魔術っぷりはみんな気になっているみたい。ちょっと突っ込んで調べようかな。

*1:もう2ヶ月も前の記事なんですね。。。遅れてるなぁ>オレ

*2:人口のカラムを男女別に分割し、GROUP BY sex, areaみたいな形で持ってくる、など