Ruby has a way of letting it know where to find classes and modules and other constants -
Rails adds some of its default directories like
app/models/*, etc. to this path. It also allows you to append to this path by adding the directory or pattern to the magical configuration
application.rb or any of the environment files like
production.rb. This setting is often leveraged by gems to add files pertaining to the gem to the
$LOAD_PATH for rails/ruby to be able to load them when required or instructed to - autoload vs eager load. There are tons of articles covering the autoload vs eager load part.
Instead I would like to talk about a small issue I noticed when abusing the loadpath, sort of, and why following Rails' conventions become necessary.
Say, you have declared a model in the path
app/models/solution/article.rb, and kept
autoload_path, Rails through ActiveSupport#safe_constantize will be able to load
Solution::Article class. This is because
app/models/solution/ like all other subdirectories are part of the
When trying to load a top level class called
Article, Rails will not be able to find it, because it simply does not exist.
Now, say, if you've added
app/models/**/* in the
autoload_path instead. This would flatten the paths so that everything is available globally. Now when
Solution::Article is tried to be load, it's available like before. But if
Article is attempted to be loaded, even that's available as
article.rb is in the
$LOAD_PATH and Rails will throw up an error saying
expected app/models/solution/article.rb to define the class Article. 🤦♂️
Hence, it is always advisable to avoid using patterns like
**/* for flattening load paths to make class definitions available. They tend to mess up how Rails resolves classes and constants and with Rails moving towards the faster and cleaner Zeitwerk library for auto/eager/reloading of classes and modules, it becomes imperative to follow clean class/namespace definition practises.