在模块中创建全局Rails方法?

use*_*929 2 ruby ruby-on-rails

我需要创建一个可以在任何情况下使用的方法(MVC,测试等).而不是在environments.rbid 中填充它就像创建一个模块并将其包含为gem.为了让Rails识别这个模块中的方法,我需要在我的gem中扩展什么类?

更新:

我正在寻找一种解决方案,允许我在没有模块前缀的情况下调用我的方法.

Nat*_*han 8

TLDR

您需要Kernel通过将方法包含在其中来"扩展" 模块include.

全球方法

通常,Ruby中的"全局"方法意味着在Kernel或中创建方法Object.然后,该方法可用于所有(大多数)类,因为它们继承自Object(包括Kernel).您可以在没有大多数地方前缀的情况下调用您的方法,因为self任何给定上下文中的隐式都是从中继承的对象,Object因此包含您定义的方法.

定义这种方法的一种方法是将其定义放在任何类或模块之外的文件中:

def my_method
  # do fancy stuff
end
Run Code Online (Sandbox Code Playgroud)

当然,您必须确保文件在某处加载(即需要).

来自模块的全局方法

如果您希望在一个模块中组织您的方法(这是一个好主意),您需要将该模块包含在Kernel这样:

module MySpecialMethods
  def my_method
    # do fancy stuff
  end
end

module Kernel
  private
  include MySpecialMethods # This is where the method gets added to Kernel
end
Run Code Online (Sandbox Code Playgroud)

在Rails中,我会把MySpecialMethods模块放入lib/,添加将Kernel部分放在初始化文件中config/initializers/extend_kernel.rb.您还需要lib/通过添加config.autoload_paths += %W(#{config.root}/lib)到application.rb 来帮助Rails"找到"您的模块

考虑避免全局方法

值得一提的是,在极少数情况下Kernel以这种方式扩展是一个好主意.有可能(可能?)对于您的情况,最好将您的方法放在一个模块中并使用模块名称显式调用它们MyModule.my_method.

module MyModule
  def self.my_method
    # do fancy stuff here
  end
end
Run Code Online (Sandbox Code Playgroud)

您可以在很多地方放置此代码.在Rails中,我建议将它放在lib/上面的文件夹中,然后确保Rails可以通过添加config.autoload_paths += %W(#{config.root}/lib)到application.rb 找到它

来自宝石

创建一个gem超出了这个问题的范围,但假设你创建了一个gem,只要你在Gemfile中指定gem,通常你的Rails应用程序中就可以使用该gem中的模块.这是因为默认情况下Rails应用程序调用Bundler.require.只要gem遵循正确的命名约定,主gem文件就会自动生成,而主gem文件需要任何其他必需的文件.

如果您想Kernel从gem Kernel扩展,只需将扩展代码(从上面)放入需要(直接或间接)需要gem的文件中.

笔记

  1. Rails初始化程序仅在您启动Rails服务器时运行一次,因此对它们的更改不会像开发中的许多其他Rails一样自动加载.

  2. 如果您正在调整Rails' autoload_paths,您可能还想调整eager_load_paths(参见此博客文章)

  3. 还有一些 Ruby的对象 没有继承Object(如BasicObject),所以在技术上这些"全球性"的方法将不可用无处不在.这不太可能给你带来麻烦.

  4. 使用Bundler.require的Rails应用程序也许是有争议的(见本博客文章关于更多信息)