如何正确加载Rails 5应用程序中的lib模块和类

4
我如何在我的模型、Grape API和测试中包含一个'lib/'类或模块呢?例如,我有一个类:
ROOT/lib/links/link.rb
module Links
  class Link
    ...
  end
end

我希望在我的用户模型 (app/models/user.rb)、用户Grape API (app/api/v1/users.rb) 和测试套件 (test/models/user_test.rbtest/api/v1/users/users_links_test.rb) 中包含该类。

例如,我尝试通过以下方式在测试中访问它:

link = Links::Link.new(LINK_NAME, LINK_SITE)

但我得到了:

uninitialized constant API::V1::Users::APITest::Links

我已经尝试将以下内容添加到我的config/application.rb文件中:

config.autoload_paths += Dir["#{Rails.root}/lib/**"]

require_relative 'boot'

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
# require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie"
require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module ArbitraryAppName
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Auto-load API and its subdirectories
    config.paths.add 'app/api', glob: '**/*.rb'
    config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
    config.autoload_paths << "#{Rails.root}/lib"

    # For Cross-Origin Resource Sharing (rack-cors)
    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :options]
      end
    end
  end
end

但是它不起作用。我漏掉了什么?我应该如何包含lib文件并如何调用这些类?
编辑: 看起来唯一能访问它的方法是这样做:require "#{Rails.root}/lib/links/link" 有更好、更常规的方法吗?
还有另一个问题,添加config.autoload_paths << whatever似乎没有任何作用。例如,当我在rails console中运行puts ActiveSupport::Dependencies.autoload_paths时,我的更改不会出现。

访问时是否出现任何错误?如果有,请添加日志。 - Prakash
1
经常推荐的方法是将 lib 文件夹移动到 app 目录下。 - Andrey Deineko
1
你的问题在于命名空间,你应该将 class Links::Link 替换为 class Link - Paul Hoffer
@AndreyDeineko:我也尝试过lib/app/links/link.rb,但我不确定如何包含它,有什么建议吗? - the_basterd
@AndreyDeineko 抱歉,那是个打字错误,我把它放在了 app/lib/links/link.rb 下面,但仍然出现了 uninitialized constant API::V1::Users::APITest::Links 错误,使用 link = Links::Link.new(LINK_NAME, LINK_SITE) - the_basterd
显示剩余3条评论
3个回答

7
不,如果你想遵循Rails的规范,就不应该使用require。Rails的自动装载是基于路径和命名空间的,因为这两个要素必须匹配。除了最初已经修复的命名空间问题外,修改自动装载路径的方式也是错误的。应该按照以下方式进行修改:
config.autoload_paths << "#{Rails.root}/lib"

如果你想把 lib/ 放在项目的根目录下,那么请按照以下步骤进行操作。如评论所述,你也可以将它移动到app/目录下。

还是不起作用...autoload_path只在生产环境中起作用吗?开发和测试环境呢? - the_basterd
你把文件移回到了 #{Rails.root}/lib 吗? - Paul Hoffer
是的,它在 #{Rails.root}/lib/links/link.rb 下。 - the_basterd
我没有application.yml文件。 - the_basterd
看起来有一个问题,我认为我的application.rb文件没有被认可,因为我添加的任何autoload_paths << whatever都没有显示出来。这是因为我没有使用ActiveRecord吗(我正在使用MongoDB/Mongoid)?我刚刚在一个新的Rails应用程序中进行了测试,使用ActiveRecord和puts ActiveSupport::Dependencies.autoload_paths显示了我的更改。 - the_basterd
显示剩余5条评论

0

Paul Hoffer的回答是被接受的答案,但是对于任何注意到config/application.rb的更改没有持久化的人:

似乎Spring存在问题,导致对config/application.rb文件的任何更改都无法持久化。我不得不运行spring stop才能使事情重新正常工作。如果有人能解释为什么有时会发生这种情况,那就太好了。


0

你不应该像Paul Hoffer建议的那样将你的lib放入autoload_paths中,因为这样做会防止它在生产环境下被急加载(当config.eager_load = true时)。

你可以在这里找到关于这个主题的详细指南:http://hakunin.com/rails3-load-paths


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接