Rails3:HOWTO覆盖/重新打开Gem中的类和Rails初始化过程

时间:2010-11-05 16:22:11

标签: ruby-on-rails ruby ruby-on-rails-3 override

我的问题与此问题非常相似:How do I add a method to a ruby gem without editing the gem source?。然而,这个问题已经差不多一年了,选择的解决方案并不是最干净的,至少对我来说不是。

提供答案的人提出了3条建议。选择第一个建议作为答案,但我真的想弄清楚如何以第二种方式做到这一点。

我需要覆盖由Gem定义的类的实例方法。更具体地说,它是SessionSerializer class in 1.1.2 Devise。问题是Devise不尊重非标准主键名称。它总是使用id。您可以在warden_compat.rb on Line 30中看到,它使用以下内容按ID查找模型:

klass.constantize.find(:first, :conditions => { :id => id })

在我的情况下,我的id列的名称为application_user_id,因此显然这不起作用。 Devise已经在1.1.3中解决了这个问题,但是我不能使用1.1.3,因为Devise LDAP Authenticatable插件不支持1.1.3。

所以这就是我所做的事情。我首先要提一下,我通过直接编辑Gem源测试了这个修复,所以现在我只想把它移到我的项目中。

  1. session_serializer.rb中创建了lib/warden/文件(即lib/warden/session_serializer.rb),重新打开了Warden::SessionSerializer类,并重新定义了deserialize方法。
  2. 修改application.rb以在lib/

    中加入config.autoload_paths
    config.autoload_paths += ["#{config.root}/lib"]
    
  3. 但是,这似乎没有办法。它仍然使用Gem源中定义的相同代码。所以我有几个问题希望可以回答:

    问题

    1. 我在这里做错了什么?
    2. Rails是否在Gems之前加载config.autoload_paths中定义的路径的文件,还是相反?
    3. 提前感谢您的帮助!

      LIB /区长/ session_serializer.rb

      module Warden
      
        class SessionSerializer
          def deserialize(keys)
            klass, id = keys
      
            if klass.is_a?(Class)
              raise "Devise changed how it stores objects in session. If you are seeing this message, " <<
                "you can fix it by changing one character in your cookie secret, forcing all previous " <<
                "cookies to expire, or cleaning up your database sessions if you are using a db store."
            end
            # NOTE: Original line code. Notice that it uses an :id symbol. It doesn't respect the primary key that explicity defined in the model
            # klass.constantize.find(:first, :conditions => { :id => id })
            # NOTE: THIS IS THE FIX
            klass.constantize.find(:first, :conditions => { :application_user_id => id })
          rescue NameError => e
            if e.message =~ /uninitialized constant/
              Rails.logger.debug "Trying to deserialize invalid class #{klass}"
              nil
            else
              raise
            end
          end
        end
      
      end
      

2 个答案:

答案 0 :(得分:3)

我会在warden.rb目录中创建一个名为initializers的文件,并将猴子补丁代码放在文件中。我经常在我的项目中使用这种技术修补宝石。

要将补丁放在lib目录下,请执行以下操作:

config.autoload_paths += ["#{config.root}/lib/warden"]

PS:我知道你已经尝试了这个,但看起来你的路径不正确。

PPS 要了解Rails 2.3加载序列,请参阅this code

答案 1 :(得分:-1)