rails/reset_session のバグ? のバックアップソース(No.1)

更新

[[公開メモ]]

#contents

* 急に Redmine にログインできなくなりました [#h1b600fc]

ログインしようとすると、

 Internal error
 
 An error occurred on the page you were trying to access.
 If you continue to experience problems please contact your Redmine administrator for assistance.
 
 If you are the Redmine administrator, check your log files for details about the error.
 
 Back

と言われる。

log/production.log を見ると、

 Processing AccountController#login [POST]
   Parameters: {"action"=>"login", "authenticity_token"=>"[FILTERED]", 
   "username"=>"[FILTERED]", "controller"=>"account", "password"=>"[FILTERED]", 
   "login"=>"ログイン »"}
 
 NoMethodError (undefined method `destroy' for {}:Hash):
   app/controllers/application_controller.rb:89:in `logged_user='
   app/controllers/account_controller.rb:203:in `successful_authentication'
   app/controllers/account_controller.rb:155:in `password_authentication'
   app/controllers/account_controller.rb:142:in `authenticate_user'
   app/controllers/account_controller.rb:30:in `login'
   /var/www/redmine/dispatch.fcgi:26

となっている。

http://www.redmine.org/boards/2/topics/23419

これと同じ症状だ。

* 原因を探る [#u6692c8e]

ログにあるエラー行の app/controllers/application_controller.rb:89 を見ると

 LANG:ruby
   # Sets the logged in user
   def logged_user=(user)
 >   reset_session
     if user && user.is_a?(User)
       User.current = user
       session[:user_id] = user.id
     else
       User.current = User.anonymous
     end
   end

reset_session の行を指している。

ん?destroy なんて無いんですけれど・・・

仕方がないので grep

 LANG:console
 $ grep reset_session app/*/* app/*/*/* app/*/*/*/*
 app/controllers/application_controller.rb:    reset_session

ここしかない。

ということは、

 LANG:console
 $ grep reset_session vendor/*/*/*/*/*
 vendor/rails/actionpack/lib/action_controller/base.rb:  # or you can remove the entire session with +reset_session+.
 vendor/rails/actionpack/lib/action_controller/base.rb:      def reset_session #:doc:
 vendor/rails/actionpack/lib/action_controller/base.rb:        request.reset_session
 vendor/rails/actionpack/lib/action_controller/flash.rb:        alias_method_chain :reset_session,  :flash
 vendor/rails/actionpack/lib/action_controller/flash.rb:        def reset_session_with_flash
 vendor/rails/actionpack/lib/action_controller/flash.rb:          reset_session_without_flash
 vendor/rails/actionpack/lib/action_controller/request.rb:    def reset_session
 vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb:        reset_session
 vendor/rails/actionpack/lib/action_controller/test_process.rb:    def reset_session
 vendor/rails/actionpack/lib/action_controller/test_process.rb:      reset_session_id
 vendor/rails/actionpack/lib/action_controller/test_process.rb:      reset_session_id
 vendor/rails/actionpack/lib/action_controller/test_process.rb:    def reset_session_id
 vendor/rails/actionpack/test/activerecord/active_record_store_test.rb:    def call_reset_session
 vendor/rails/actionpack/test/activerecord/active_record_store_test.rb:      reset_session
 vendor/rails/actionpack/test/activerecord/active_record_store_test.rb:      get '/call_reset_session'
 vendor/rails/actionpack/test/activerecord/active_record_store_test.rb:      get '/call_reset_session'
 vendor/rails/actionpack/test/controller/flash_test.rb:    def use_flash_after_reset_session
 vendor/rails/actionpack/test/controller/flash_test.rb:      reset_session
 vendor/rails/actionpack/test/controller/flash_test.rb:  def test_flash_after_reset_session
 vendor/rails/actionpack/test/controller/flash_test.rb:    get :use_flash_after_reset_session
 vendor/rails/actionpack/test/controller/test_test.rb:      reset_session
 vendor/rails/actionpack/test/controller/test_test.rb:  def test_session_is_cleared_from_controller_after_reset_session
 vendor/rails/actionpack/test/controller/test_test.rb:  def test_session_is_cleared_from_response_after_reset_session
 vendor/rails/actionpack/test/controller/test_test.rb:  def test_session_is_cleared_from_request_after_reset_session

ruby のデバッグってこういう感じだっけ・・・ orz

で、発見したのがこれ。

vendor/rails/actionpack/lib/action_controller/request.rb
 LANG:ruby
    def reset_session
      session.destroy if session
      self.session = {}
    end

reset する際に Hash を代入してるのに、
再度リセットする際に Hash が持っていない 
destroy という関数を呼んでいる。

そりゃだめだ。

session.destroy の行を

 LANG:ruby
      session.destroy if session and session.respond_to?(:destroy)

としたらどうかしら?

というものすごい monkey patch を試したところ、今のところ動いているみたい?

(アプリケーションをリセットしたせいかもしれないので、しばらく様子見)

* コメント [#lcdc419b]

#article_kcaptcha

Counter: 20477 (from 2010/06/03), today: 7, yesterday: 0