Posted filed under Publications, Ruby on Rails.

デブサミ2008のデブサミライブ 2/13 14:20-の枠で、BlazeDSをRubyから扱う話をします。
BlazeDS(Java), Ruby, AIR(ActionScript)と扱う言語だけは多いですが、マニアックな話ので、誰もこないんじゃないかと心配です。

内容的には、BlazeDS+AIR+Rubyを使って企業向けインスタンスメッセンジャーを作る話をします。
殆ど時間をPCに向かっているこの業界では、内線電話よりもメッセンジャーの方が便利な事も多々あると思います。
しかし、GTalkやMSNメッセンジャーはセキュリティの問題があり使えない、、、
そんな企業の為に、簡単に作れるメッセンジャーをご紹介します。
多分、同時に100人以上が接続しても大丈夫。はなず。クラスタリングもできるっぽいし。

そして、いまそのサンプルを間違って消してしまって、作り直しちゅう。。。。。
サンプルだから、svnに突っ込んでなかったんだよなぁ。

Posted filed under Life.

自分でもびっくりな話なのですが、Life is beautifulの中島さんのサポートをいただき、今年3月に渡米&起業をする事になりました。
場所はシアトル近郊の予定ですが、MS関係じゃーありませんw

元々、昨年4月に渡米を前提としてワイズノットに入社したのですが、夏ぐらいから実現が困難な事に気がつき、別の方法を探していました。
そんな中、中島さんと知り合う事ができ、自分で起業して渡米するという、予想外の道を辿る事になりました。
この辺はいろいろは話があるので、そのうちどっかに書きます。

渡米で起業と言っても「アメリカで一山当てるぜ!」とか、「今までやってきた事を世界展開」いうテンションはなく、特にはじめのうちは、現在日本で行っているRailsでの開発や、新サービス立ち上げのお手伝いなどを、そのまま行っていこうと思っています。
生活に慣れたら、独自サービスの構築などを考えて行こうかなと、まったり考えたりしています。

なので、オンラインでも出来る仕事があるから、発注してやってもいいよ、という方がいましたら、masui(あっと)masuidrive.jpまでメールをいただけると助かります。
2/13のデブサミが、最後の講演になりますが、ちょっと飯でも食べてみようかなという方も、ご連絡お待ちしています。

スケジュール的には、2月末で千葉を離れ、一度北海道に戻り、3月中旬に渡米の予定です。
まだなにかあるのか自分でもよくわかっていませんが、がんばります。

p.s
ワイズノットには、民事再生の話を聞く前に年末での退職願を出してありました。
なので、ほんとにびっくりしました。

Posted filed under Ruby on Rails.

別にPHPの話題とは関係ないのですが、PHP見たいにHTMLにぺっとコードを貼って動かしたいなーというケースはRailsでアプリを組んでいて思う事が多々あります。

ヘルプページは静的なHTMLなんだけど、レイアウトはRails部分と共用したいなーとか、ヘッダ部分にログイン中のユーザ名だけは入れておきたいなーとか。

そこで、そんなときのため、http://example.com/helpにアクセスすると、RAILS_ROOT/erb/help.html.erbが実行されるような仕組みを考えてみました。めんどくさいのでプラグインにはしていません。

ルートファイルと、アプリケーションコントローラに下記のコードを追加してください。

config/routes.rbの最後の行に追加

   map.connect '*path', :controller => 'application', :action => 'rescue_404' if ::ActionController::Base.consider_all_requests_local

app/controllers/application.rbの適当な所に追加

  def rescue_404
    absolute_root = File.join(File.expand_path(RAILS_ROOT),'')
    template = File.expand_path(File.join('erb', *params[:path]), RAILS_ROOT)
    if template.index(absolute_root) == 0
      template = File.join(template, 'index') if File.directory?(template)
      ['.html.erb', '.erb', '.rhtml'].each do |ext|
        return render(:file => template+ext) if File.file?(template+ext)
      end
    end
    render :file => File.join(RAILS_ROOT, 'public', '404.html')
  end

これで、RAILS_ROOT/erbディレクトリを作り、そこにerbファイルを置くと直接実行することができるようになります。
ApplicationControllerから呼ばれて実行されるので、アプリによってはログイン中のユーザ情報なども取得する事ができると思います。

p.s
前回のCookieSessionのjpmobile対応はあきらめました。色々ややこしいことが分かってきたので。。。

Posted filed under Ruby on Rails.

こっちが、ほんとの目的。地味に開発を続けているSticka.jpの携帯対応の為に必要なので。
AIR版とWeb版を同時にリリースするつもりだったのに、AIRの日本語は相変わらずダメダメなので、とりあえずWeb版ばかり開発が進んでます。

すでに十分使える様になったので、前に登録していただいた人を中心に近々ベータテストを開始します。

このコードはうまく動きません。対応はあきらめました。 (追記 2008/02/03)

さて、このStickaはRails 2.0で作っています。セッションはCookieStore。どうせuser_idしか保存しないしね。
でも、そうするとクッキーを持たない携帯では使えない。それじゃ困る。
という事で書いてみました。jpmobileのtrans sidを使ってCookieStoreをパラメータに保存。
セキュリティ的にかなり微妙なので、使う人は気をつけてください。
とくにリファラーは一発です。

i-modeのブックマークのURLは256文字までらしいので、別に対策が必要です。

jpmobile/lib/jpmobile/trans_sid.rb

# 〜〜 省略 〜〜
class CGI::Session::CookieStore #:nodoc: # ↓追加
  def marshaled_data #:nodoc:
    if defined?(@data) && !@data.blank?
      updated = marshal(@data)
      raise CookieOverflow if updated.size > MAX
      return updated
    end
    nil
  end
end # ↑追加


module Jpmobile::TransSid #:nodoc:
  # 〜〜 省略 〜〜
  protected
  # URLにsession_idを追加する。
  def default_url_options(options)
    return unless request # for test process
    return unless apply_transit_sid?
    { session_key => session_id }  # 変更
  end

  private
  # 〜〜 省略 〜〜  # ↓追加
  # session_idを返すが、CookieStoreだった場合は、データを返す
  def session_id
    session.dbman.is_a?(CGI::Session::CookieStore) ? session.dbman.marshaled_data : session.session_id
  end # ↑追加
  
  # session_idを埋め込むためのhidden fieldを出力する。
  def sid_hidden_field_tag
    "<input type=¥"hidden¥" name=¥"#{CGI::escapeHTML session_key}¥" value=¥"#{CGI::escapeHTML session_id}¥" />" # 変更
  end
  # 〜〜 省略 〜〜

Posted filed under Ruby on Rails.

Cookieが使えないDoCoMoなどの端末で、uriにセッションキーを追加するtrans_sidが、Rails 2.0系で動かないっていう話があったので、気分転換に手を動かしてみました。

http://dev.rubyonrails.org/browser/tags/rel_2-0-2/actionpack/lib/action_controller/cgi_ext/session.rb
Railsのセッションは、Ruby標準のCGI::Sessionを使っています。ここでSessionを生成する時にCGIのオブジェクトから、クッキーやパラメータを見てセッションを生成してます。
そこで、このセッション生成のときを調べてみると、CGI#paramsが空でパラメータが渡っていません。

http://dev.rubyonrails.org/browser/tags/rel_2-0-2/actionpack/lib/action_controller/cgi_ext/query_extension.rb
CGIの生成を追っていると、そもそも生成時にCGI#paramsを{}で上書きしています。

これは、CSRF対策のようです。これを上書きするのもちょっとなんな気がするので、セッション生成時にパラメータを再構築する様にしてみます。

jpmobile/lib/jpmobile/trans_sid.rb に下記のパッチを追加してください。

class ::CGI #:nodoc:
  class Session #:nodoc:
    alias_method :initialize_without_uri_session_key, :initialize
    def initialize(cgi, options = {})
      cgi.params[options['session_key']] ||= ENV['RAW_POST_DATA'] ? CGI.parse(ENV['RAW_POST_DATA'])[options['session_key']] : CGI.parse(cgi.query_string)[options['session_key']] if @cgi.cookies[options['session_key']].empty?
      initialize_without_uri_session_key(cgi, options)
    end
  end
end

このままだと、jpmobileをインストールするだけで、セッションキーをパラメータで受け取る様になってしまいます。
本当は最低でもtrans_sidが起動された場合にのみ、このパッチが走る様にしないとな。
携帯用にするなら、携帯からのアクセスの場合のみURIパラメータでセッションキーを受け取る様にしたいなぁ。

このパッチは、作者のShidara君に送ってあるので、数日中に取り込まれると思います。

続いて、CookieStoreをパラメータに埋め込む様にしたいなぁ。

Posted filed under Ruby on Rails.

http://dev.rubyonrails.org/browser/tags/rel_2-0-0

Rails2.0でました!
rubyforgeではパッケージが公開されているので、数時間でgemでもインストールできるようになるでしょう。

ActiveModelを楽しみにしてたんだけど、やっぱり空っぽ・・・。
http://dev.rubyonrails.org/browser/tags/rel_2-0-0/activemodel/lib/active_model
これが正式版でいいのか?
つうかこんだけ広範囲に影響するものをRC1で入れるあたりが怖いなぁ。

Posted filed under Javascript.

 グラフが簡単に生成できるAPI、Google Chart APIが公開されたので、早速使ってみました。

 Railsのプラグインとかは誰かが作ってくれるだろうから、自分でやらないとして、気になるのは日本語が通るのか。

早速試してみたところ、ひらがなは通るが漢字や長音記号は通らない。おしい。あと一歩。

修正 13:47
Typo: 感じ→漢字
矢崎さんありがとうございました。

追記 14:20
弾さんの所で、ブラウザから簡単に試せるフォームが公開されてます。

Posted filed under Ruby on Rails.

mixiでも使われているって言う全文検索エンジンHyperEstraier。mixiの膨大な件数を処理するぐらいだから相当スケーラビリティもあるだろなーとおもいつつ、SQLだけで全文検索できちゃうMySQL+Sennaが便利なんで、そっちばっかり使ってました。

MySQL+Senna(Triton)も、PostgreSQL+Senna(Ludia)も、属性付きで検索した場合、Sennaで全文検索してから、その答えをSQLで絞り込みを行っているようで、たとえば、個人のメッセージを保存しているテーブルを検索した場合など、属性の値が多い場合には、かなり効率が悪くなる事が見えてました。

本当は、メッセージみたいなものは、個人ごとにインデックスをもって処理するべきなんだろうなと思っていて、SennaでやるかHyperEstraierでやるか迷いつつ、ぐぐっていたところ、HyperEstraierがどんぴしゃりな機能を持っているのを発見しました。

疑似ノードマスタという機能で、大量のインデックスを保持することが容易にできるようです。

この疑似ノードマスターの話は、おいおい調べるとして、まずはRailsからHyperEstraierを触ってみます。

というほどのものではなく、acts_as_searchableというプラグインを使えば、ほぼ意識することなく、HyperEstraierを扱えるようです。

このプラグインは単純な全文検索だけでなく、属性検索などもサポートしており、通常の用途であれば、これで事が足りそうです。

# estcmd create -tr -attr @user_id num messages
class Message < ActiveRecord::Base
  acts_as_searchable :searchable_fields => [:subject, :body], :attributes => {:user_id => :user_id}
end

と指定する事で、下記の様に特定ユーザのメッセージだけ検索するという事ができます。

Message.fulltext_search("masuidrive",  :attributes => "user_id NUMEQ %d" % User.find_by_name('guest'))

このプラグインで、注意が必要なのは、検索対象として指定したカラムのsetterメソッドが定義されている点です。
この場合は、subject=, body=, user_id=が上書きされます。
プラグインの実行タイミングなどから、define_method_chainは使えないようなので、これらのメソッドを上書きするときは、そのメソッドの中から値を更新するときに、write_attributeの代わりに、write_changed_attributeを呼ぶ様にしてください。

以上、バットノウハウでした。

属性検索の演算子は、ユーザーズガイドの検索条件式を見てください。通常の=演算子などは使えません。