如何从app / modules扩展ActiveRecord?

时间:2011-06-09 05:27:24

标签: ruby-on-rails ruby ruby-on-rails-3 metaprogramming extend

我想在我的应用中使用几种不同的acts_as _...自定义类方法。我希望这些方法的代码位于app / modules目录中的文件中。

我无法让这个工作。

例如,我有一个文件:app / modules / 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:未定义的局部变量或   方法`acts_as_lockable'

我的猜测是我不应该自动加载模块文件夹,因为我扩展它时已经加载了ActiveRecord?还有另一种方法吗?我希望能够在开发期间更改文件而无需重新启动我的服务器,但这更像是一种需要。

2 个答案:

答案 0 :(得分:7)

我认为你是以错误的方式思考这个问题。

您正在将此模块添加到加载路径

但只有在你说出来时才会加载;

require 'acts_as_lockable'

ActsAsLockable

我建议你永远不要在你的代码中说出其中任何一个。

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

我建议您创建一个名为“config / initializers / 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

然后在初始化器中

** config / initializers / acts_as_lockable.rb **

require 'acts_as_lockable'
ActiveRecord::Base.extend ActsAsLockable

答案 1 :(得分:0)

问题是ruby自动加载机制是一个惰性进程:当在代码中使用类似ActsAsLockable的常量时,它会在autoload_paths中查找名为acts_as_lockable.rb的文件。由于您从未真正使用ActsAsLockable,因此文件永远不会被加载。你可以做(​​虽然不是很漂亮):

ActsAsLockable

class MyModel < ActiveRecord::Base
  acts_as_lockable

  ...
end

我认为使用acts_as_ *模式可以使用插件和gem来轻松地将功能集成到代码中。当您将插件和宝石集成到项目中时,它们应该处于最终状态,因此您不需要为开发模式重新加载功能。

我希望这会有所帮助。