How to properly load lib modules and classes in Rails 5 app

ruby, ruby-on-rails

Solution

No, you shouldn't resort to using require (if you want to follow Rails conventions). Rails autoloading is based on paths and namespacing, as those two things have to match up. Besides the initial problem with namespacing that was fixed, the way you modify the autoload paths is incorrect. It should be done this way:

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

This is if you want to leave `lib/` at the root of your project. As mentioned in the comments, you could move it into your `app/` directory.

Problem

How do I include a '`lib/`' class or module in my models, Grape API and tests? For example, I have a class: `ROOT/lib/links/link.rb` ``` module Links class Link ... end end ``` And I want to include that class in my User model (`app/models/user.rb`), User Grape API (`app/api/v1/users.rb`), and testing suites (`test/models/user_test.rb` and `test/api/v1/users/users_links_test.rb`) For example, I tried accessing it in my tests through `link = Links::Link.new(LINK_NAME, LINK_SITE)` but I get: `uninitialized constant API::V1::Users::APITest::Links` I've tried adding this to my `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 ``` but it doesn't work. What am I missing? How do I include `lib` files and how should I be calling those classes? EDIT: It seems like the only way I can access it is if I do: `require "#{Rails.root}/lib/links/link"` Is there a better, more conventional way? There seems to be another issue, adding `config.autoload_paths << whatever` does not seem to be doing anything. For example, when I `puts ActiveSupport::Dependencies.autoload_paths` in `rails console`, my changes do not appear.

Original source