ruby on rails-如何从应用程序/模块扩展ActiveRecord



我有几个不同的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

在应用程序.rb

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

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

NameError:未定义的局部变量或方法`acts_as_lockable'

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

我认为您的想法是错误的。

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

但只有当你说;

require 'acts_as_lockable'

ActsAsLockable

我建议您永远不要真的想在代码中说出这两个。

你正在寻找的正确范例是"初始化器"。

我建议您创建一个名为"config/ininitializers/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/ininitializers/acts_as_lockable.rb**

require 'acts_as_lockable'
ActiveRecord::Base.extend ActsAsLockable

问题是ruby自动加载机制是一个懒惰的过程:当在代码中使用像ActsAsLockable这样的常量时,它会在autoload_path中查找一个名为acts_as_lockable.rb的文件。由于您从未实际使用ActsAsLockable,因此该文件从未加载。你可以做(虽然不是非常漂亮):

ActsAsLockable
class MyModel < ActiveRecord::Base
  acts_as_lockable
  ...
end

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

我希望这能有所帮助。

最新更新