Rails3で簡単なサンプルを作ってみた スレッド式掲示板です。

レスは追加できるけど、スレッド追加する機能は作り忘れた。

Mongoid版

http://github.com/func09/rails3_sample_bbs/tree/mongoid-20100813

ActiveRecord版

http://github.com/func09/rails3_sample_bbs/tree/activerecord-20100813

それぞれのREADMEに従えば動くはず。 rake db:seed でサンプルデータがインサートされるます。

Rails3だからといって、別段特殊なコードは書けなかった。 よくもわるくもいつもどおり書けた。

http://github.com/func09/rails3_sample_bbs/zipball/mongoid-20100813

http://github.com/func09/rails3_sample_bbs/zipball/activerecord-20100813

Posted in ruby, ruby on rails at 8月 16th, 2010. No Comments.

みんな大好きRuby on Railsも、RCが出て、いよいよバージョン3登場間際といった感じですね 2010年8月30日にリリースされました。

ベータ版をいれるのはちょっと・・と尻込みしていた人(僕)も、やっと重い尻を上げてみようじゃないかと思わなくもないのではないでしょうか?

そこで、Rails3のリリース前にチェックすべき事などをメモします。

RVMをインストールして、Rails2とRails3の環境を共存させる

Rails3から、railsコマンドの挙動が大きく変わっているので、これまでのRails2も使う必要がある場合は、RVMで複数のRuby環境を準備しておくのが良いです。

Ruby Freaks Lounge 第39回 RVM(Ruby Version Manager)による環境構築
http://gihyo.jp/dev/serial/01/ruby/0039

Ruby Freaks Lounge 第40回 RVM(Ruby Version Manager)による環境構築(2)
http://gihyo.jp/dev/serial/01/ruby/0040

※追記を参照のこと

Rails2 と Rails3 の違いを、ざっくりっと学ぶ

いままで慣れ親しんだRails2のインターフェイスは、結構互換性があるので、移行に関してものすごく大きなインパクトがあるわけではないようです。

Rails2との違いを比較しながら、Rails3の新しい部分を紹介した素晴らしいスクリーンキャストがあります。 各コンポーネントごとに動画が用意されていて、資料のPDF(全86ページ)もとてもわかりやすく、一度Rails2を学んだ人であれば、ひととおり流せばRails3の新機能を把握できると思います。

Dive into Rails3
http://rubyonrails.org/screencasts/rails3

上記のプレゼン資料(PDF)
http://assets.en.oreilly.com/1/event/40/The%20Rails%203%20Ropes%20Course%20Presentation.pdf

時間がないひとはPDFを見るだけで十分ですよ。

Rails2のプロジェクトをRails3にアップデートする

既存のRails2プロジェクトをRails3にアップデートする方法は、RailsCastsで紹介されています。

Upgrading to Rails 3 Part 1
http://railscasts.com/episodes/225-upgrading-to-rails-3-part-1

Upgrading to Rails 3 Part 2
http://railscasts.com/episodes/226-upgrading-to-rails-3-part-2

Enjoy Rails3!

追記:2010-08-30

RVMはGemによるインストールが非推奨なので、こちらの方法に従うのがよいとのことです(by @babie)。

http://rvm.beginrescueend.com/rvm/install/

Posted in ruby, ruby on rails at 8月 10th, 2010. No Comments.

PaperClipでクロッピングしたい場合の書き方メモ

has_attached_file :picture, :styles => { :thumb => "200x200#" }

サイズ指定の後ろに「#」で切り抜きになるようだ

Posted in ruby, ruby on rails at 8月 6th, 2010. No Comments.

Rails使いの味方Herokuネタです。

HerokuでRailsアプリをデプロイする場合、タイムゾーン設定にちょっと癖があります。

Read More…

Posted in ruby, ruby on rails at 7月 28th, 2010. No Comments.

ツイッターに匿名で投稿できるサービスを作りました。

つぶやき@名無しさん http://nanasi3.com/

Read More…

Posted in Webサービス, ruby, ruby on rails at 7月 9th, 2010. No Comments.

NiftyGeneratorとは?

すごくニッチな話題になってしまいますが Railsでサクっとモックを作る時、僕はnifty_generatorを使います

http://github.com/ryanb/nifty-generators

nifty_generatorはRailsCastsのryanb作の、サクっと便利でシンプルなコードを生成してくれるパッケージで

  • レイアウト
  • Scaffold
  • 設定ファイル
  • 認証処理

を生成するコマンドを提供してくれます。

RailsCasts内のサンプルアプリケーションは、いつもnifty_generatorを使ってますね。

標準のGeneratorスクリプトに比べて良い点は

  • デザインがシンプルだけど適度に良く、拡張する土台にしやすい
  • レイアウトが良くできている
  • レイアウトだけ生成できる

という具合です。

特にScaffoldしなくてもレイアウトを生成してくれるのは、非常に便利なので僕は常用しているのですが、

最近ViewをHamlで書くようになってから、ちょっと不便だなぁと感じていました。

Haml対応してた

ヘルプみたら、普通に対応してるし・・。

script/generate nifty_layout --haml
create app/views/layouts
create public/stylesheets
exists app/helpers
create public/stylesheets/sass
create app/views/layouts/application.html.haml
create public/stylesheets/sass/application.sass
create app/helpers/layout_helper.rb

すごい!かわいい!nifty_layout!

そして僕はどんどんコードをエディタで書かなくなるんだ!

Posted in ruby on rails at 6月 29th, 2010. No Comments.

Facebooker

FacebookerはRuby on Rails用のFacebookプラグインです。
Facebookアプリケーションを作ったりFBMLのヘルパーがあったりREST APIへのラッパーが用意されていて、大変に便利が良いです。

使い方は

チュートリアル
http://apps.facebook.com/facebooker_tutorial/

Developing Facebook Platform Applications with Rails http://www.pragprog.com/titles/mmfacer/developing-facebook-platform-applications-with-rails

を参考にしてください。
書籍の方はちょっと情報が古いのですが、それでも十分役立ちます。

ユーザー情報の取得方法

Facebookerでのユーザー情報の取得は、とてもRails的でわかりやすいです。

script/console で実行する場合

  1. # Facebook ユーザーID
  2. facebook_id = 1234567890
  3.  
  4. # Facebookのセッションキー
  5. session_key = 'xxxxxxxxxxxxxxxxxxxxxxxxx'
  6.  
  7. # Facebook APIにアクセスするためのセッション作成
  8. fb_session = Facebooer::Session.create
  9. fb_sessoin.secure_with!(fb_sessoin, facebook_id, 1.hour.from_now)
  10.  
  11. fb_session.user #=> セッションユーザー情報。Facebooker::Userのインスタンス
  12. fb_session.user.friends #=> セッションユーザーの友人のユーザー情報。Facebooker::Userインスタンスの配列


ユーザー情報の取得には、Users.getInfo APIを利用する。

ユーザー情報のキャッシュ

Facebooker::Userインスタンスは、生成された後、最初にプロパティ(#name, #age ..etc)にアクセスしたタイミングでUsers.getInfo APIにリクエストを投げる。一度リクエストしたら、2度目はキャッシュしたメモリから値を返す。

Facebooker::Userインスタンスを作成しても、プロパティにアクセスしなければUsers.getInfo APIをリクエストしないので、少しはパフォーマンスに効果があるのかもしれない。

  1. user = fb_session.user # まだREST APIにリクエストしてない
  2. user.name #=> 'Yukio Hatoyama' このタイミングでREST APIにリクエストしている
  3. user.sex #=> 'Male' メモリーから取得


同じユーザーでもキャッシュは効かない場合がある、ていうかほとんど。

基本的にはインスタンス変数にデータを蓄えているだけなので、同じFacebookユーザーでもオブジェクトが違えば、キャッシュは当然効いていないため、それぞれAPIへリクエストすることになる。

  1. # UID123456789のユーザー
  2. user = Facebooker::User.new(123456789, fb_session)
  3. # users.getInfo APIにアクセスする
  4. user.name #=> 'Yukio Hatoyama'
  5.  
  6. # 同じUIDを持つユーザー
  7. sameuser = Facebooker::User.new(123456789, fb_session)
  8. # Users.getInfo APIにアクセスする
  9. sameuser.name #=> 'Yukio Hatoyama'


フレンド情報の取得

Facebookerでのフレンド情報取得は、Facebooker::User#friendsを利用することになる。 このようなAPIがFacebookに存在しているわけではなくて、Friends.get APIで友人のID一覧を取得した後にその人数分Users.getInfo APIをリクエストしにいっている。

従って、かなり効率が悪いです・・。

  1. user = Facebooker::User.new(123456789, fb_session)
  2. user.friends #=> Userインスタンスの配列コレクション。友達が20人いれば、リクエスト数は21回。


フレンド情報のキャッシュ

フレンド情報の取得にはキャッシュが効く。効かなかったらやばいよね。

  1. user = Facebooker::User.new(123456789, fb_session)
  2.  
  3. # フレンド数分、users.getInfo APIをリクエスト
  4. user.friends
  5.  
  6. # メモリのキャッシュから返すので、APIはリクエストしない
  7. user.friends
  8.  
  9. # プロパティを指定した場合、もう一度人数分リクエストする
  10. user.friends([:name, :sex])
  11.  
  12. # キャッシュから返すのでAPIはリクエストしない
  13. user.friends([:name, :sex])


これもUserインスタンス内の変数にキャッシュしているだけだから、あまり効果なさそうだなぁ。。

最後に

FacebookerはFacebookアプリをRubyで作りたい場合、とても便利です。
情報も他のライブラリに比べて一番充実していると思います。

僕もこれまでFacebook関連のアレをやってきましたが、Facebookerのインターフェイスの良さにはしびれっぱなしです。

キャッシュに関しては、FacebookのユーザーIDベースでKey Value Storeに保持しておけるようにできたらいいなと思っていますが、Facebookの規約的にアウトじゃないのか?とか、そもそもユーザー情報の見え方がユーザーによっては違うはずなので、やっぱりサービス全体でキャッシュするのはダメかなぁ。

追記

Facebooker::User#users(ids)メソッドを使えば、リクエストが1回で済むことがわかった。
基本的にはこっちを使おうかな。

Posted in ruby, ruby on rails at 2月 19th, 2010. 1 Comment.

Railsで最近人気の認証フレームワーク「Authlogic」は、ユーザーセッションをまるでActiveRecord風なモデルのように扱えることによって、セッション周りの処理をコントローラーからモデル側へ移すことができていて、コードがシンプルになります(コントローラーがごちゃごちゃしないという点で)。

AuthlogicではユーザーセッションをAuthlogic::Session::Baseを継承したクラスで管理するようになっており

  1. # user_session.rb
  2. class UserSession <Authlogic::Session::Base
  3. end
  4.  
  5. # ログインする
  6. session = UserSession.new(:login => "bjohnson", :password => "my password", :remember_me => true)
  7. session.save
  8.  
  9. # ログインしているユーザーセッションを取得する
  10. current_user_session = UserSession.find
  11.  
  12. # ログアウトする
  13. session.destroy


と、こんな感じのインターフェイスでログイン周りの処理が書けて、非常にわかりやすい。

しかし隠蔽されているとはいえ、モデルからセッションやCookieにアクセスするといった事を自分で実装したことがなかったので、一体どんな仕組になっとるんか?と考え調べました。

読んだポインタ

http://github.com/binarylogic/authlogic/blob/master/lib/authlogic/controller_adapters/abstract_adapter.rb
http://github.com/binarylogic/authlogic/blob/master/lib/authlogic/controller_adapters/rails_adapter.rb

3行で説明

  1. ActionControllerのbefore_filterの先頭で
  2. ActionControllerをラップしたアダプタークラス(RailsAdapter)への参照を
  3. Authlogic::Session::Base.controllerに代入している

モジュールをインクルードしている箇所 http://github.com/binarylogic/authlogic/blob/master/lib/authlogic/controller_adapters/rails_adapter.rb#L48

  1. ActionController::Base.send(:include, Authlogic::ControllerAdapters::RailsAdapter::RailsImplementation)


コントローラーの先頭のフィルターに:activate_authlogicという処理を追加している箇所 http://github.com/binarylogic/authlogic/blob/master/lib/authlogic/controller_adapters/rails_adapter.rb#L36

  1. klass.prepend_before_filter :activate_authlogic


Authlogic::Session::Base.controllreにコントローラーのアダプターを代入している箇所 http://github.com/binarylogic/authlogic/blob/master/lib/authlogic/controller_adapters/rails_adapter.rb#L40-42

  1. def activate_authlogic
  2.   Authlogic::Session::Base.controller = RailsAdapter.new(self)
  3. end


とても勉強になったんだけど、Authlogicはソースが綺麗に分割されすぎてて探しにくい。

Posted in ruby, ruby on rails at 2月 15th, 2010. No Comments.

Railsで非同期処理?

railsで非同期処理をやる場合、最近はdelayed_jobメジャーらしいですね。

以前はbackgrounDRbが定番だったようだけど、EngineYardが「友達にBackgrounDRbを使わせるな」とまで書いているので、そこまで言われると使う気になりませんでした。実際リソース食いだったし。

使い方参考ページ

使い方はそんなに難しくないので、ここで説明することは放棄します。

READMERailscastsのエピソード171でなんとかなると思います。

再試行のロジック

いろいろとすっとばして本題、キューの再試行のロジックが変だなぁと思ったのでメモです。

Delayed::Job::max_attempts

delayed_jobには試行回数上限があって、この上限値を超えるまでリトライしつづけます。 デフォルトは25回で、Delayed::Job::max_attempts という定数に設定されています。

Delayed::Worker::sleep_delay

ワーカーが起動するインターバルです。デフォルトは5秒。

例えば絶対に失敗するキューがあった時、

  1. キュー失敗、5秒待機、キュー失敗、5秒待機、(以下25回失敗するまで繰り返し)


という流れを勝手にイメージしていたのですが、そうではないみたいです。

キューが失敗した時の再スケジューリング

キューが失敗すると、次に実行する予定時刻を決めます。そのロジックが

On failure, the job is scheduled again in 5 seconds + N ** 4, where N is the number of retries.

となっています。

「トライした回数の4乗に5秒足した時間」後にリトライをするよう再スケジューリングするので、失敗すればするほどインターバルが開いていきます。

1回失敗したら次回のリトライは6秒後
2回失敗したら次回のリトライは21秒後
3回失敗したら次回のリトライは86秒後
4回失敗したら次回のリトライは261秒後
5回失敗したら次回のリトライは630秒後
6回失敗したら次回のリトライは1301秒後
7回失敗したら次回のリトライは2406秒後
8回失敗したら次回のリトライは4101秒後
9回失敗したら次回のリトライは6566秒後
10回失敗したら次回のリトライは10005秒後

最初の方は1分以内にリトライさせますが、10回目ともなるとリトライは2時間後。
何度も失敗していると、もうこいつアカンわ・・と見捨てられていく感じを良く表現したロジックですねー。

Posted in ruby on rails, 日記 at 12月 15th, 2009. No Comments.

なんかto_jsonについて調べてたら

activerecord/lib/active_record/serializers/json_serializer.rb

にらきすたのこなたが出てくるんだけど、これって有名なんだろうか・・。

あまりにも意外すぎて、なんの作業してたか忘れたよ。いい迷惑だ!

http://github.com/rails/rails/blob/55501b9f6ab46d45db04a81956579402511ad092/activerecord/lib/active_record/serializers/json_serializer.rb#L18-75

--

追記:

例えばこんな感じ、コメントの中にサンプルコードとして登場します

  1. #   konata = User.find(1)
  2.     #   ActiveRecord::Base.include_root_in_json = true
  3.     #   konata.to_json
  4.     #   # => { "user": {"id": 1, "name": "Konata Izumi", "age": 16,
  5.     #                   "created_at": "2006/08/01", "awesome": true} }


はてブのコメントによると2年前からコードの中に存在していたらしい。
アニメ好きな外人のコミッターが犯人だったんすね。

http://blog.codefront.net/2007/10/15/konata-izumi-in-edge-rails/

Posted in ruby on rails at 11月 2nd, 2009. No Comments.