2009-07-02 47 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