2009-07-02 140 views
76

我正在为open_flash_chart插件编写自定义封装。它被放置在/lib中并作为模块加载到ApplicationController中。Rails/lib模块和

但是,我有一些类层次结构或水手问题。

从任何控制器我可以访问open_flash_chart功能OpenFlashChartLine

然而,在一个类中/lib模块,它不工作!

任何想法?

回答

143

有一些文件Rails中得到加载两种方式:

  • 它注册在自动加载的过程,您引用对应于文件名的常量。例如,如果您有app/controllers/pages_controller.rb和引用PagesController,则会自动加载app/controllers/pages_controller.rb。这发生在加载路径中的预设目录列表中。这是Rails的一个特性,并不是普通Ruby加载过程的一部分。
  • 文件明确require d。如果文件为require d,Ruby会查看加载路径中的整个路径列表,并找到第一个情况,即require d在加载路径中的文件。您可以通过检查$ LOAD_PATH($的别名)来查看整个加载路径。

由于lib是在您的负载路径,你有两个选择:要么具有相同名称的常量命名文件,所以Rails会自动接他们,当你引用常数问题,或明确要求模块。

我还注意到你可能会对另一件事感到困惑。 ApplicationController是而不是系统中的根对象。注意:

module MyModule 
    def im_awesome 
    puts "#{self} is so awesome" 
    end 
end 

class ApplicationController < ActionController::Base 
    include MyModule 
end 

class AnotherClass 
end 

AnotherClass.new.im_awesome 
# NoMethodError: undefined method `im_awesome' for #<AnotherClass:0x101208ad0> 

您将需要包括模块插入要在使用它的任何类

class AnotherClass 
    include MyModule 
end 

AnotherClass.new.im_awesome 
# AnotherClass is so awesome 

当然,为了能够包括模块中的首位,你需要使用它(使用上述任何一种技术)。

+2

只是想要添加:如果/ lib(或其中一个自动加载目录)中的某个模块已经定义;例如你重载ActiveRecord或String,你必须明确地要求它或它不会被加载 – Mike 2010-12-07 10:50:45

+1

奇怪,我得到:未初始化的常量GaClient(NameError),除非我需要事先'ga_client'(类定义在LIB/ga_client.rb)。是否有自动加载命名方案的文档? – mkirk 2011-04-15 20:58:21

80

在Rails 3/lib模块不会自动加载。

这是因为行:

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

内部配置/ application.rb中被注释。

你可以试着去掉这一行,或者(它为我工作更好),离开这个评论(备查),并添加这两条线:

config.autoload_paths += %W(#{config.root}/lib) 
config.autoload_paths += Dir["#{config.root}/lib/**/"] 
+0

这将复制`ApplicationName :: Application.config.autoload_paths`数组中的`../ lib`路径。 – jibiel 2012-01-23 11:30:56

19

什么工作对我来说,除了在取消config.autoload_paths(我在Rails 3.1上。3),是要创造一个像这样的初始化:

#config/initializers/myapp_init.rb 
require 'my_module'  
include MyModule 

这样我可以调用MyModule的方法从任何地方和类方法Model.mymodule_method或实例方法mymodel.mymodule_method

也许有些专家可以解释的影响这个的。现在,使用它需要您自担风险。

编辑:之后,我想一个更好的approuch是:

创建这样的初始化:

#config/initializers/myapp_init.rb 
require ‘my_module’ 

包括其中所需要的模块,像这样:

1)如果您想将其用作“分类方法”,请使用“扩展”:

class Myclass < ActiveRecord::Base 
    extend MyModule 
    def self.method1 
     Myclass.my_module_method 
    end 
end 

2)如果你想使用它作为“实例方法”包括IT类的定义中:

class Myclass < ActiveRecord::Base 
include MyModule 
    def method1 
     self.my_module_method 
    end 
end 

3)记住,include MyModule指的是在你的负载路径下的文件my_module.rb必须需要首先

0

在应用程序初始化时,您可能需要在lib目录下显式加载文件。
在我的config/application.rb中,我有一个条目:
config.autoload_paths += %W(#{config.root}/lib)

此外,这可能是模块名称/层次结构与文件中的不同,或者文件的位置/名称与该层次结构不同,因此该文件的自动加载也是不可能的。所以当我在config/application.rb底部添加一个条目时,它的效果很好,
require "./lib/file_name_without_extention

2

使用模块lib/my_module.rb在你的模型和控制器:

config/application.rb

config.watchable_dirs['lib'] = [:rb] 

在你的模型(你的控制器类似的想法):

require_dependency 'my_module' 

class MyModel < ActiveRecord::Base 
    include MyModule 

    MyModule.some_method 
end 

这种方法更详细地描述在http://hakunin.com/rails3-load-paths