2011-06-09 53 views
6

我有几个不同的acts_as _...自定义类的方法我想在我的应用程序中使用。我希望这些方法的代码位于app/modules目录中的文件中。如何从应用程序/模块扩展ActiveRecord?

我一直无法得到这个工作。

举例来说,我有一个文件:应用程序/模块/ acts_as_lockable

module ActsAsLockable 

    def acts_as_lockable 
     before_create :set_lock 

     include InstanceMethods 
    end 

    module InstanceMethods 
     protected 

     def set_lock 
      now = Time.now.to_s 
      self.lock = Digest::SHA1.hexdigest(now) 
     end 
    end 

end 

ActiveRecord::Base.extend ActsAsLockable 

而且在application.rb中

config.autoload_paths += %W(#{config.root}/app/modules) 

当我尝试加载调用acts_as_lockable我得到的一个模型以下错误:

NameError: undefined local variable or method `acts_as_lockable'

我的猜测是我不应该自动加载模块文件夹bec当我扩展ActiveRecord时,它已经被加载了吗?有没有另一种方法来做到这一点?我希望能够在开发过程中更改文件,而不必重新启动服务器,但这更多是需要的。

回答

7

我认为你正在以错误的方式考虑这个问题。

你加入这个模块负载路径,

,但如果你或者说只会加载;

require 'acts_as_lockable' 

ActsAsLockable 

我建议你从来没有真正想说的任一代码内。

您正在寻找的正确范例是“初始化程序”。

我建议你创建一个名为“配置/初始化/ acts_as_lockable.rb”

文件在此文件中,您可以包括整个代码,

或只包括require 'acts_as_lockable'

通常我把这样的东西放在libs目录下

确保lib位于加载路径中

** config/application。RB **

config.autoload_paths += %W(#{config.root}/lib) 

** LIB/acts_as_lockable.rb **

module ActsAsLockable 

    def acts_as_lockable 
    before_create :set_lock 

    include InstanceMethods 
    end 

    module InstanceMethods 
    protected 

    def set_lock 
     now = Time.now.to_s 
     self.lock = Digest::SHA1.hexdigest(now) 
    end 
    end 

end 

然后在初始化

**配置/初始化/ acts_as_lockable.rb **

require 'acts_as_lockable' 
ActiveRecord::Base.extend ActsAsLockable 
+0

谢谢你的魅力。我意识到这可能不是最实际的解决方案,但出于某种原因,我讨厌在我的模型中看到包含声明。 – tanman 2011-06-09 21:40:13

0

问题是,ruby自动加载机制是一个懒惰的过程:当在代码中使用像ActsAsLockable这样的常量时,它会在autoload_paths中查找名为acts_as_lockable.rb的文件。由于您从来没有真正使用过ActsAsLockable,所以文件永远不会被加载。你可以这样做(虽然不是极大漂亮):

ActsAsLockable 

class MyModel < ActiveRecord::Base 
    acts_as_lockable 

    ... 
end 

我觉得acts_as_ *模式彪BE插件和宝石用来方便地功能集成到你的代码。将插件和宝石集成到项目中时,插件和宝石应该处于最终状态,因此您不需要为开发模式重新加载功能。

我希望这会有所帮助。