Rails / lib模块和


83

我正在为open_flash_chart插件编写自定义包装。它已放入其中,/lib并作为模块加载到中ApplicationController

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

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

但是,在/lib模块的类中,它不起作用!

有任何想法吗?


Answers:


147

将文件加载到Rails中的方式有​​两种:

  • 它在自动加载过程中注册,并且您引用一个与文件名相对应的常量。例如,如果您拥有app/controllers/pages_controller.rb并引用PagesController,app/controllers/pages_controller.rb它将自动加载。对于加载路径中的预设目录列表,会发生这种情况。这是Rails的功能,不是正常Ruby加载过程的一部分。
  • 文件是明确的required。如果文件是required,则Ruby会遍历加载路径中的整个路径列表,并找到第一种情况,即required文件位于加载路径中。您可以通过检查$ 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

1
奇怪的是,我得到:未初始化的常量GaClient(NameError),除非我事先需要'ga_client'(该类在lib / ga_client.rb中定义)。是否有有关自动加载命名方案的文档?
mkirk 2011年

87

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

这是因为该行:

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

config / application.rb中的内容被注释。

您可以尝试取消注释此行,或者,(对我而言,它甚至更好),请保留此注释(以供将来参考),并添加以下两行:

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

这将复制数组中的../lib路径ApplicationName::Application.config.autoload_paths
jibiel 2012年

1
@jibiel那么这里的分辨率是多少?
ylluminate 2012年

4
为什么后一种选择对您更有效?另外,为什么更改默认设置...尽管有很多人在寻找解决方法,但一定有一个原因。
ckarbass

@ylluminate所以一个config.autoload_paths += Dir["#{config.root}/lib/**/"]就足够了。@ckarbass第二行使您可以自由地将实用程序组织到子文件夹中,从而使用命名空间简化模块。就是这样。这就是更改默认设置的原因。迟到总比没有好:)
jibiel 2014年

对我来说这似乎有些混乱。这不会不必要地自动加载rake任务吗?
丹尼斯

22

除了取消注释config.autoload_paths(我在Rails 3.1.3上)外,对我有用的是创建一个像这样的初始化程序:

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

这样,我可以在任何地方以类方法Model.mymodule_method或实例方法调用mymodule方法mymodel.mymodule_method

也许有些专家可能会解释这一点的含义。现在,使用它需要您自担风险。

编辑:之后,我认为更好的方法是:

创建一个这样的初始化程序:

#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)如果您要将其用作“实例方法”,请将其包含在类定义中:

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

3)请记住,它include MyModule指向my_module.rb您的加载路径中必须首先需要的文件


3
我已经在lib文件夹中创建了模块,因此已添加config.autoload_paths += %W(#{config.root}/lib)config/application.rb文件。之后,我按照您的建议添加config/initializers/myapp_init.rb文件及其内容。一切都是好的。非常感谢:)
SMMousavi

即使require对我有用require,自动加载也不起作用(未定义的模块方法),但此注释表示您不应使用
丹尼斯

3

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


0

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

也可能是模块名称/层次结构与文件中的名称不同或文件的位置/名称与该层次结构不同的情况,因此自动加载该文件也是不可能的。因此,当我在config / application.rb的底部添加一个条目时,
require "./lib/file_name_without_extention
它工作正常。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.