OpenId Authentication Pluginのサンプルにはまった。
最近RailsのOpenIdAuthentication Pluginに挑戦しています。
open_id_authenticationプラグインの導入はこちらを参考にしました。
open_id_authentication*[認証][Rails] open_id_authenticationをつかってみる - KazusaAPI開発日誌 - KDRIグループ
koress.jp: 解消法: open_id_authenticationプラグイン(rails 2.0.2)
サンプルを動かしてみてOpenID Profider(IdP)からリダイレクトされてくるところまではスムーズに行ったのですが、その後のレスポンスを解析する部分で、このプラグインに添付してあるサンプルソースに潜んだバグ(?)にはまりました。
具体的にハマったのは、サンプルソース内の以下の部分で使われているcase .. when構文の比較ルール。
-
authenticate_with_open_id do |result, identity_url|
-
case result
-
when :missing
-
failed_login "Sorry, the OpenID server couldn't be found"
-
when :canceled
-
failed_login "OpenID verification was canceled"
-
when :failed
-
failed_login "Sorry, the OpenID verification failed"
-
when :successful
-
if @current_user = @account.users.find_by_identity_url(identity_url)
-
successful_login
-
else
-
failed_login "Sorry, no user by that identity URL exists (#{identity_url})"
-
end
-
end
-
end
ここでは以下のような評価を想定されているようです。
-
status === :missing
ちなみにこの「===(code)」メソッドは
-
RAILS_ROOT/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb
にて、内部クラスResultに定義されています。
(参考:/plugins/open_id_authentication/lib/open_id_authentication.rb - Rails Trac - Trac)
しかしcase .. when構文で実行される比較命令は
-
(whenの引数)=== (caseの引数)
となるようで、実行されるのは以下の比較命令になります。
-
:missing === status
この場合、Symbolクラスのオブジェクトである「:missing」とResultクラスのオブジェクトである「Result[:missing]」が、Symbolクラスに定義された「===(var)」メソッドで比較されるので、当然「false」になります。
Plugin作者的には、Resultクラスの「===(code)」メソッドでResult内部の「@code」と引数のシンボルを比較することを想定しているのだと思いますが、実際にはここでは全ての比較がSymbolクラスの「===(var)」で行われ、結果としてどのwhen句も実行されることはありません。
ここが全く分からずに、本当にはまりました...
-
A===B
と
-
B===A
が違うなんて...Rubyは(僕には?)まだまだ奥深い。
結局最終的には
-
RAILS_ROOT/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb
のResultクラス内に
-
def code
-
@code
-
end
というメソッドを追加して、先ほどのcaseの引数をresultではなくresult.codeとすることで、以下のコードは期待通りに動作するようになりました。
-
authenticate_with_open_id do |result, identity_url|
-
case result.code
-
when :missing
-
failed_login "Sorry, the OpenID server couldn't be found"
-
when :canceled
-
failed_login "OpenID verification was canceled"
-
when :failed
-
failed_login "Sorry, the OpenID verification failed"
-
when :successful
-
if @current_user = @account.users.find_by_identity_url(identity_url)
-
successful_login
-
else
-
failed_login "Sorry, no user by that identity URL exists (#{identity_url})"
-
end
-
end
-
end
やれやれ、まさかこんなところではまるとは...
このプラグイン、作者DHHらしいんですが、「===(code)」をどうやって使うつもりだったんだろう??
僕の使い方が間違っているのかなぁ〜??












この記事がお役に立ちましたら、一言コメントもらえると嬉しいですm_ _m