iPhone + Facebook でアプリ作ってみました - FAUploader

on 2011/09/27 - 0 Comments -



何のおもしろみもないですが、せっかく作ったので公開します。説明は iTunes のコピペで。

FAUploader @ iTunes

This application makes it easier and faster to upload photos to your facebook albums.

How to use:

1. Select Albums ( once you choose, you can skip this step )
2. Take Photo ( or choose from library )
3. Upload

Features:

1. Easy upload to albums
You can select an album to upload and once you choose an album, you can upload photos to that album continuously.

2. Fast upload
App automatically compresses photos and it enables you to upload faster than facebook native app.

I'd be pleased to get some feedback. Thank you.

incompatible character encodings: ASCII-8BIT and UTF-8

on 2011/09/25 - 1 Comments -

Rails の View での表示の際に incompatible character encodings: ASCII-8BIT and UTF-8 でエラーする件について。

エンコーディングが違う文字列を連結しようとすると発生するそうで、layout を入れ子にしていたりすると発生するとか。解決策としては文字列のエンコーディングをすべて utf-8 にそろえればよいとのことで、以下の通り実装。

ちなみに環境は Ruby 1.9.2 と Rails 3.0.9 です。この組み合わせはクサいらしい。


lib/encoding_patch.rb
module ActiveSupport
  class SafeBuffer < String
    def concat(value)
      if value.html_safe?
        super(value.force_encoding('utf-8'))
      else
        super(ERB::Util.h(value.force_encoding('utf-8')))
      end
    end
    alias << concat
  end
end




config/environment.rb
require 'encoding_patch'



確かにこれでエラーは出なくなりました。

参考:
Ruby1.9+Rails3で"incompatible character encodings: UTF-8 and ASCII-8BIT"の対策
# application.rb じゃなくて environment.rb に書くと思った

div をリンクにする

on 2011/09/20 - 0 Comments -

div に a タグと同じ動きをさせたいことは多々ある。

1.js に以下を追加

div の中の a タグの href 属性を取得して、window をそこに遷移する処理、また hover した時に背景色を帰る処理を追加(後者は必須じゃないけど、この方がカッコイイので)。


my.js
$(function(){
     $(".aDiv").click(function(){
         window.location=$(this).find("a").attr("href");
         return false;
    });
});

$(function(){
    $(".aDiv").hover(
	function(){
	    this.style.backgroundColor = "#f9f9ff";
	},
	function(){
	    this.style.backgroundColor = "white";
	}
    );
});



2.css に以下を追加

div にマウスが重なったらカーソルの見た目をポインタにする。


my.css
.aDiv{ cursor: pointer }



3.html を書く

リンクの動きをさせる div を書く。


my.html
<div class="aDiv">
  <a href="http://some.site.url">SomeSite</a>
</div>



以上。

Ruby on Rails on Heroku + Facebook

on 2011/09/19 - 0 Comments -

Facebook が Heroku と正式に連携したので使ってみたメモ。

アナウンスおよびチュートリアル:
Facebook and Heroku: an even easier way to get started

Heroku では Rails が動くので、Rails で手軽に Facebook App が作れるようになったということですね。

1.Facebook から Heroku にアプリを追加

上のチュートリアルを読めば分かるはず。ポチポチとボタンを押すだけ。

2.Heroku で Rails でアプリを作成する

1で作られるアプリは Pure Ruby なので、自分で作った Rails アプリに入れ替える。とりあえず Facebook のことは考えず、以下の手順をもとに Heroku で Rails のアプリが動くところまで進める。

Getting Started with Heroku
Getting started with Rails 3.0 on Heroku/Cedar

* Heroku では PostgreSQL を使うので開発環境にも必要かも
* バージョンは Ruby が 1.9.2 、Rails が 3.0.9 でした

3.Facebook と連携

Rails が動くようになったら、Facebook が自動で作ってくれたものと入れ替え。
以下あたりを参考に。

Building a Facebook Application With Ruby
Getting Started with Your Facebook App on Heroku
Herokuで作るFacebookアプリ

皇居(10km)

on 2011/09/18 - 0 Comments -

久々の皇居。
秋の気配は感じられなかった。

9月:22km

家の周り(4km)

on 2011/09/17 - 0 Comments -

お墓の周辺が最近のジョギングコースです。

9月:12km

Being Geek

これからのキャリアとわりと重なる気がして読んでみました。



サブタイトルが「ギークであり続けるためのキャリア戦略」とあり、会社での立ち振る舞い方や上司との付き合い方、会社を移る時の話など、ある意味で真っ当にキャリアを形成していくために必要な Tips が満載です。また内容的にも意外と一般的なものが多く、ギークでなくても気付かされる点は多々あると思いました。

個人的に印象に残ったのは23章の「ナード」ハンドブックのところで、特に「ナード」を理解するというセクションでは自分のことをありのまま書かれているような気がしてかなりドキッとしました。恥ずかしいので知り合いの方は読まないでください。笑

筆者の経験をもとに実用的なノウハウがユーモアを交えて書いてあり、自分のなかにスッと入ってきます。定期的に読み返したい本の1つです。

補足:ギークについては以下参照のこと。
http://ja.wikipedia.org/wiki/ギーク

大規模サービス技術入門

on 2011/09/16 - 0 Comments -

nifty で「ココログ」を作り、はてなで「はてなブックマーク」を作り CTO をやっていた伊藤さんの本。これから僕も大規模サービスやるので今更ながら読んでみました。



自分なりにざっくりと内容をまとめると、以下でしょうか。

1.ユーザー・情報が膨大となった時、単にスケールするだけはでなく、仕組み自体を変えないといけない

2.その時考えるべきは、キャッシュ、データ構造、アルゴリズムの3つ

せっかくなので簡単にこの2つについて書きます。


1.ユーザー・情報が膨大となった時、単にスケールするだけはでなく、仕組み自体を変えないといけない

データベースについての話が一番おもしろかったのでここで取り上げます。

ご存知の通りデータベースには様々な情報を格納することができますが、様々な制限から無限に情報を格納できるわけではなくて、必ず限界があります。扱う情報が膨大となり、その限界を超えてしまうことは容易に想像できます。その時どうするかという話です。

現状よくやられる対応として、情報を分割して複数のデータベースに分けて格納するというものがあります。例えば 100 しか入らないデータベースに 10,000 を入れたければ、情報を 100 ずつ 100 個に分割して、100 のデータベースに分けて格納する感じです。当然分割には規則があり、欲しい情報がどのデータベースにあるかは分かるようになっています。

発想としてはわりと単純ですが、データベースを複数台用意するコスト、複数台から目的の情報を持ったデータベースを選択するコストがわりと小さいので、現状とても現実的な方法と言えます。

# しかしながらやっぱりそれ面倒くさいよってことで、次世代のデータストアとしてその辺よしなにやってくれる Cassandra などが注目されているようです。(補足1)


2.その時考えるべきは、キャッシュ、データ構造、アルゴリズムの3つ

キャッシュ、データ構造、アルゴリズムと書きましたが、結局のところ、データへのアクセス速度をできる限り上げて、計算量をできる限り減らそうということです。

キャッシュが重要というのは、メモリからの読み出し速度がハードディスクと比べて  10 万から 100 万倍速いためです。ほしい情報ができるだけメモリから読み出せれば、それだけでかなり高速化できるということです。僕も昔これで 3h の処理が ~10s になりました。使いそうな情報はできるだけメモリに乗せちゃいましょう。

memcached とかまさにこの仕組みで、キャッシュからの読み出しで高速に動作し、大量のリクエストをさばきます。Facebook, Twitter も使っているやらいないやら。(補足2)

データ構造とアルゴリズムですが、n^2 のオーダーには気をつけましょう、インデックス張りましょうというよくある話です。基本的な事項ですが無視すると大変なことになるのでとても重要ですね。

最後に

大規模サービスとかその辺の話はノウハウベースの色が強くて、正直やってみないと分からないと思ってましたが、この本を読んで大分イメージが湧きました。また大規模なサービスに関係ない人もキャッシュの話は一般論としてとても大切だと思うので読んでおいて損はないかと思いました。

以上。
# あーなんかすげー長くなってしまった。。

補足1:
Cassandra実践入門―Twitter,Facebookが採用するNoSQLシステム
TwitterとDiggがNoSQLの「Cassandra」を選ぶ理由

補足2(ちょい古い):
Twitterの大規模システム運用技術、あるいはクジラの腹の中(後編)
Facebookが大規模スケーラビリティへの挑戦で学んだこと(後編)


Facebook 認証で期限切れ accessToken が取得される件

on 2011/09/13 - 2 Comments -

iOS での Facebook 連携の際 accessToken がうまく取得できない問題がありました。

1.事象

認証の際に期限切れの accessToken が取得される。

もう少し詳しく書くと、FBAppAuth という Safari で Facebook のページを開かずに API から直接リクエストを出す方式で認証する場合に発生しました。なぜか3日前に期限の切れた accessToken が取得されるという謎。。

2.回避策

以下の通り Facebook.m を編集して、強制的に Safari での認証方式をとるようにしました。

(認証が必要な時には Safari がアクティブになり、認証後にディアクティブになるという動作になります。)


Facebook.m
- (void)authorize:(NSArray *)permissions
       localAppId:(NSString *)localAppId {
  self.localAppId = localAppId;
  self.permissions = permissions;

//    [self authorizeWithFBAppAuth:YES safariAuth:YES];
    [self authorizeWithFBAppAuth:NO safariAuth:YES];
}



なお通常は FBAppAuth が YES となっていて、アプリをインストールした iPhone が対応していれば(*)FBAppAuth を使って認証を行うようになっています。

* バージョンが 3.4.1 以上の Facebook App がインストールされている場合だそうです

3.補足

Facebook との連携では isSessionValid で Session が有効か判断しますが、判断基準は結局のところ、Facebook インスタンス内に保持している「期限切れ時刻」と「現在時刻」の比較でした。
# accessToken が nil じゃないか、なども確認していますが


Facebook.m

- (BOOL)isSessionValid {
  return (self.accessToken != nil && self.expirationDate != nil
           && NSOrderedDescending == [self.expirationDate compare:[NSDate date]]);

}



感覚的には isSessionValid は accessToken が期限切れでなく、ちゃんと使えることを担保してくれていてほしいのですが、実はそんなことはありませんでした、ということになります。

またここで注目するべきは、「期限切れ時刻」があと何秒間 accessToken が有効かという情報をもとにクライアント側で計算されたものということです。厳密には accessToken と結びついてはいません。

具体的には accessToken 取得時に一緒に受け取る expires_in という秒数を、accessToken 取得時の時刻に足したものが「期限切れ時刻」になっています。

ソースを見ると早いですが、expires_in を引数にした dateWithTimeIntervalSinceNow: で現在時刻からの時刻を取得しています。


Facebook.m
- (BOOL)handleOpenURL:(NSURL *)url {
...
NSString *expTime = [params valueForKey:@"expires_in"];
NSDate *expirationDate = [NSDate distantFuture];
if (expTime != nil) {
  int expVal = [expTime intValue];
  if (expVal != 0) {
    expirationDate = [NSDate dateWithTimeIntervalSinceNow:expVal];
  }
}
...



なので、isSessionValid が YES だったとしても、accessToken の期限が切れていないことは必ずしも保証されません。
# Facebook 側ではちゃんと返す実装になっていると思いますが。

実際、今回の事象では「期限切れ時刻」的には OK である accessToken を http://developers.facebook.com/tools/explorer/ で確認してみると、以下のメッセージが表示されてエラーとなりました。


OAuthException: Error validating access token: Session has expired at unix time xxx. The current unix time is yyy.



原因はまだちゃんと分かっていませんが、以前取得した accessToken と全く同じものを取得しているようなので、なんとなくキャッシュされてるんじゃないか、もしくは全く同じリクエストが飛んでいるんじゃないかと思ってます。Facebook.m か FBRequest.m あたりをちゃんと見たら分かりそうです。

と長々書きましたが、とりあえず FBAppAuth を NO にして、SafariAuth をYES にしておけば、Safari で問題なく認証してくれるので、取り急ぎこの期限切れの accessToken が取得される問題は回避できるようです。

以上。

家周辺(4km)

on 2011/09/11 - 0 Comments -

体が信じられないくらい重かった。
寝起きだったからと信じたい。

9月:8km

家周辺(4km)

on 2011/09/04 - 0 Comments -

引っ越してから初。
コース開拓をもくろみつつ軽くジョグ。

9月:4km