【问题标题】:Override or add methods to already loaded Classes覆盖或添加方法到已加载的类
【发布时间】:2026-01-14 12:35:01
【问题描述】:

我正在尝试向 ActiveSupport::TimeWithZone 类添加功能,并将以下文件添加到我的 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 目录中使用其他自定义模块,但是这个似乎被忽略了。知道为什么吗?

【问题讨论】:

  • 你为什么认为它被忽略了?
  • 我用行为更新了问题

标签: ruby-on-rails ruby activesupport


【解决方案1】:

所有猴子补丁通常存储在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'

希望对您有所帮助。

【讨论】:

  • 谢谢你,你是对的,但弗雷德里克更好地解释了整个比例
【解决方案2】:

其实 Rails 远比你想象的要聪明,你在autoload_paths 数组中输入的路径是为了将来使用。在development 环境eager loading 的类中,如果放置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

【讨论】:

  • 谢谢你,你是对的,但弗雷德里克更好地解释了整个比例
【解决方案3】:

当您尝试使用未定义的常量时,Rails 会为您加载代码:调用 rails 设置的 const_missing 挂钩,搜索 autoload_paths 以查找名称与常量对应的文件,然后需要它。

在您的情况下,永远不会调用此代码:TimeWithZone 类是在加载 rails 本身的过程中加载的。

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

【讨论】: