the_basterd the_basterd - 1 month ago 26
Ruby Question

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

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.

Answer

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.

Comments