すごくニッチな話題になってしまいますが Railsでサクっとモックを作る時、僕はnifty_generatorを使います
http://github.com/ryanb/nifty-generators
nifty_generatorはRailsCastsのryanb作の、サクっと便利でシンプルなコードを生成してくれるパッケージで
を生成するコマンドを提供してくれます。
RailsCasts内のサンプルアプリケーションは、いつもnifty_generatorを使ってますね。
標準のGeneratorスクリプトに比べて良い点は
という具合です。
特にScaffoldしなくてもレイアウトを生成してくれるのは、非常に便利なので僕は常用しているのですが、
最近ViewをHamlで書くようになってから、ちょっと不便だなぁと感じていました。
ヘルプみたら、普通に対応してるし・・。
すごい!かわいい!nifty_layout!
そして僕はどんどんコードをエディタで書かなくなるんだ!
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 で実行する場合
ユーザー情報の取得には、Users.getInfo APIを利用する。
Facebooker::Userインスタンスは、生成された後、最初にプロパティ(#name, #age ..etc)にアクセスしたタイミングでUsers.getInfo APIにリクエストを投げる。一度リクエストしたら、2度目はキャッシュしたメモリから値を返す。
Facebooker::Userインスタンスを作成しても、プロパティにアクセスしなければUsers.getInfo APIをリクエストしないので、少しはパフォーマンスに効果があるのかもしれない。
基本的にはインスタンス変数にデータを蓄えているだけなので、同じFacebookユーザーでもオブジェクトが違えば、キャッシュは当然効いていないため、それぞれAPIへリクエストすることになる。
Facebookerでのフレンド情報取得は、Facebooker::User#friendsを利用することになる。 このようなAPIがFacebookに存在しているわけではなくて、Friends.get APIで友人のID一覧を取得した後にその人数分Users.getInfo APIをリクエストしにいっている。
従って、かなり効率が悪いです・・。
フレンド情報の取得にはキャッシュが効く。効かなかったらやばいよね。
これもUserインスタンス内の変数にキャッシュしているだけだから、あまり効果なさそうだなぁ。。
FacebookerはFacebookアプリをRubyで作りたい場合、とても便利です。
情報も他のライブラリに比べて一番充実していると思います。
僕もこれまでFacebook関連のアレをやってきましたが、Facebookerのインターフェイスの良さにはしびれっぱなしです。
キャッシュに関しては、FacebookのユーザーIDベースでKey Value Storeに保持しておけるようにできたらいいなと思っていますが、Facebookの規約的にアウトじゃないのか?とか、そもそもユーザー情報の見え方がユーザーによっては違うはずなので、やっぱりサービス全体でキャッシュするのはダメかなぁ。
Facebooker::User#users(ids)メソッドを使えば、リクエストが1回で済むことがわかった。
基本的にはこっちを使おうかな。
Railsで最近人気の認証フレームワーク「Authlogic」は、ユーザーセッションをまるでActiveRecord風なモデルのように扱えることによって、セッション周りの処理をコントローラーからモデル側へ移すことができていて、コードがシンプルになります(コントローラーがごちゃごちゃしないという点で)。
AuthlogicではユーザーセッションをAuthlogic::Session::Baseを継承したクラスで管理するようになっており
と、こんな感じのインターフェイスでログイン周りの処理が書けて、非常にわかりやすい。
しかし隠蔽されているとはいえ、モデルからセッションや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
モジュールをインクルードしている箇所 http://github.com/binarylogic/authlogic/blob/master/lib/authlogic/controller_adapters/rails_adapter.rb#L48
コントローラーの先頭のフィルターに:activate_authlogicという処理を追加している箇所 http://github.com/binarylogic/authlogic/blob/master/lib/authlogic/controller_adapters/rails_adapter.rb#L36
Authlogic::Session::Base.controllreにコントローラーのアダプターを代入している箇所 http://github.com/binarylogic/authlogic/blob/master/lib/authlogic/controller_adapters/rails_adapter.rb#L40-42
とても勉強になったんだけど、Authlogicはソースが綺麗に分割されすぎてて探しにくい。
railsで非同期処理をやる場合、最近はdelayed_jobがメジャーらしいですね。
以前はbackgrounDRbが定番だったようだけど、EngineYardが「友達にBackgrounDRbを使わせるな」とまで書いているので、そこまで言われると使う気になりませんでした。実際リソース食いだったし。
使い方はそんなに難しくないので、ここで説明することは放棄します。
READMEとRailscastsのエピソード171でなんとかなると思います。
いろいろとすっとばして本題、キューの再試行のロジックが変だなぁと思ったのでメモです。
delayed_jobには試行回数上限があって、この上限値を超えるまでリトライしつづけます。 デフォルトは25回で、Delayed::Job::max_attempts という定数に設定されています。
ワーカーが起動するインターバルです。デフォルトは5秒。
例えば絶対に失敗するキューがあった時、
という流れを勝手にイメージしていたのですが、そうではないみたいです。
キューが失敗すると、次に実行する予定時刻を決めます。そのロジックが
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時間後。
何度も失敗していると、もうこいつアカンわ・・と見捨てられていく感じを良く表現したロジックですねー。
なんかto_jsonについて調べてたら
activerecord/lib/active_record/serializers/json_serializer.rb
にらきすたのこなたが出てくるんだけど、これって有名なんだろうか・・。
あまりにも意外すぎて、なんの作業してたか忘れたよ。いい迷惑だ!
–
追記:
例えばこんな感じ、コメントの中にサンプルコードとして登場します
はてブのコメントによると2年前からコードの中に存在していたらしい。
アニメ好きな外人のコミッターが犯人だったんすね。
http://blog.codefront.net/2007/10/15/konata-izumi-in-edge-rails/
RailsでApplicationHelperのスペックを書くときにハマったのでメモ。
まず普通にスペックを書く場合
spec/helpers/appliction_helper_spec.rbを以下のように準備
helper_nameでへルーパー名を定義しておくのがポイント。
そしてExampleの中から「helper」を通じて、エクスペクテーションを書いていきます。(言葉の使い方あってる?)
ヘルパーメソッドの中でリクエストを参照する場合(そもそもヘルパーがリクエストを参照するのが美しいことなのか疑問を抱きましたが、とりあえず無視)
ApplicationControllerにスタブアクションを作ってあげる、というやり方でなんとかしました。
こんな感じで、普通にコントローラースペックを書くときのようにgetとかpostとかヘルパースペックの中からリクエストを使ったテストを一応かけます。
もっと良い方法がある気がする。
個人的メモ
結構リソース食うので次はdelayed_jobにしたい・・
Amazon CloudFrontはAmazon S3上のファイルをキャッシュするソリューションです。
前回paperclipからS3を使う設定はわかったので、今回はさらにCloudFrontを利用するための設定です
前回こんな感じでS3の設定をしました。
コンソールから利用してみると
こんな感じでS3のURLがとれるようになっているはず。
キャッシュサービスであるCloudFrontを利用する場合は、ホスト名を適宜変えるだけなので paperclipが勝手にやってくれるといいなぁ〜なんて思いました。
オプションが2つ増えてます
わーーこりゃ幸せだ。
さらにサイト全体でアセット関係(public以下)もCloudFrontにしたければ
config/environments/#{RAILS_ENV}.rb 内で
こうしとけば、image_path()やらimage_tag()やらjavascript_include_tag()やらを使ったときに、リクエスト先を書き換えてくれてさらに幸せ度アップ