覆盖或添加已加载的方法 类

Override or add methods to already loaded Classes

我正在尝试向 ActiveSupport::TimeWithZone 添加功能 class 将以下文件添加到我的 rails 项目:

lib/active_support/time_with_zone.rb

class ActiveSupport::TimeWithZone
  def in_time_zone_(new_zone = ::Time.zone)
    Time.zone.parse(in_time_zone(new_zone).strftime('%a, %d %b %Y %H:%M:%S'))
  end
end

并在

config/application.rb

config.autoload_paths << "#{Rails.root}/lib"

我可以在我的 lib 目录中使用其他自定义模块,但这个模块似乎被忽略了。知道为什么吗?

所有猴子补丁通常存储在 config/initializers 目录中。 我把你的代码放在 config/initializers/active_support_time_with_zone.rb

这是我的例子

2.1.2 :005 > r = Reason.last
  Reason Load (0.1ms)  SELECT "reasons".* FROM "reasons" ORDER BY "reasons"."id" DESC LIMIT 1
 => #<Reason id: 3, name: "R3", project_id: 3, created_at: "2016-05-04 06:43:25", updated_at: "2016-05-04 06:43:25", deleted: false>
2.1.2 :006 > r.created_at.class
 => ActiveSupport::TimeWithZone
2.1.2 :007 > r.created_at.in_time_zone_
 => Wed, 04 May 2016 06:43:25 UTC +00:00
2.1.2 :010 > Time.zone = "Novosibirsk"
 => "Novosibirsk"
2.1.2 :011 > Time.zone
 => #<ActiveSupport::TimeZone:0x007fbcd695ad90 @name="Novosibirsk", @utc_offset=nil, @tzinfo=#<TZInfo::TimezoneProxy: Asia/Novosibirsk>, @current_period=nil>
2.1.2 :012 > r.created_at.in_time_zone_
 => Wed, 04 May 2016 13:43:25 NOVT +07:00
2.1.2 :013 >

我使用了你提供的代码

class ActiveSupport::TimeWithZone
  def in_time_zone_(new_zone = ::Time.zone)
    Time.zone.parse(in_time_zone(new_zone).strftime('%a, %d %b %Y %H:%M:%S'))
  end
end

我的应用使用 gem 'rails', '4.0.3'

希望对您有所帮助。

其实Rails远比你想象的聪明,你放在autoload_paths数组中的路径是为了以后使用。在 development 环境 eager loading of 类 if put off。因此 类 仅在您的代码需要时才加载到内存中或 required

需要时,Rails 通过 classnamespace 搜索 file

示例
如果它看到 ActiveSupport::TimeWithZone 它期望路径是 lib/active_support/time_with_zone.rb

lib 在那里是因为您将 lib 目录放在数组中。

但是initializers目录不是这样。因为这个目录中的所有文件都被认为是重要的并且在 Rails 启动时加载。

查看此内容了解更多信息 http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoload-paths

Rails 在您尝试使用未定义常量时为您加载代码:调用 const_missing 钩子 rails 设置,搜索 autoload_paths 文件一个对应常量的名称,然后需要它。

在您的情况下,永远不会调用此代码:TimeWithZone class 是在 rails' 本身加载期间加载的。

您可以将您的猴子补丁放在总是加载的东西中(例如在初始化程序中),或者从初始化程序中明确要求它。