Rails Autoloading is what happens in the background that most developers don’t even think about. The Rails Autoload is something that is important for you to know about. Rails will automatically load certain files your Rails app application when it boots up.
When you first learn Rails you learn about its basic structure:
We call this “MVC” for “model-view-controller.”
Then you get a little more experience and you learn about domain architecture and services. Perhaps you make a new Rails app and you notice an empty folder
And you look at this folder and you think, “What do I put there?”
Sometimes you must use the ‘require’ keyword to load files—- as you see in specs often— but sometimes you don’t. When do you use ‘require’ and when don’t you?
Rails has an important piece of magic that’s significant for every new Rails dev to know: the autoload with same-name, or correctly named, files. That is, Rails will autoload files for you if you meet the three conditions below.
Before letting you in on the secret, lets review the concepts of underscores, titlecase and namespaces.
An underscore is a character on your keyboard (probably to the right of the 0 on your number line). On most keyboards you press SHIFT-(-). Press SHIFT and the dash key to produce an underscore, which looks like this: _ . The underscore appears where the underline would just below where a letter would be, but denotes that there is no letter or number. Do not confuse the underscore with the dash, which appears in the middle of the line. On your keyboard, you don’t hold SHIFT to create a dash character, and you do hold shift to create an underscore.
What does the underscore mean? The underscore means the space of “no character” when in fact it does represent a character in the computer’s implementation. Because loading from operating systems is finicky with spaces, we don’t use spaces in our file names. Instead we use underscores.
Here are some examples of Ruby files with underscores in them. You always use underscores when naming the actual files on your disk. (Even though your operating system might actually allow you to put a space in a file name, don’t do this when naming Ruby files.)
Titlecase refers to a special syntax used by Ruby and some other programming languages to represent objects. In short, if you have several words, you make each of the first letters of each word uppercase and then you string the words together. So, if you have a phrase like “something wicked this way comes” to make it title case would look like:
Note how we capitalize (uppercase) the first letter of each word but the other letters are not capitalized. Also notice how there are no spaces or underscore separating the words. We call this titlecase and it is how we write all objects in Ruby. (Do not confuse titlecase with camelcase, often found in other programming languages, which is very similar to titlecase but the very first letter of the whole object name is lower case. In our example, the camelcase of what we have above would be
somethingWicketThisWayComes with lowercase
s in something)
Namespace or Namespacing
A namespace, or namespacing (the act of applying a namespace), is really just when we want to group things together and give them a common element in their name, typically prepended (or put before). In Rails, we have a special way to namespace (explained below) using subfolders. But, if, for example, we wanted all parts of our application involving subscription management to be under the name ‘subscriptions,’ we might (actually, as I will explain below, we can and should) move our Ruby objects into a subfolder called ‘subscriptions’ and also namespace our objects by renaming them
Subscriptions:: plus what we first called them.
A namespace is really just a way for programmers to group ideas together (and truly, it is probably a relatively poor way to think about object abstraction. The examples provided in this post provide examples of what I would call good use of namespacing. If you find a large system that is highly namespaced or is overly convoluted, you may have some antipatterns. This is because developers overused namespacing, or relied on it when they should have created more extensible encapsulations. This advanced subject is beyond the scope fo this post. Just keep in mind that namespacing, while a quick way to clean up small messes, should not be overused when what you really need are better abstractions.)
OK, now the 3 magic rules of the Rails autoload:
Your Rails files will be loaded by Rails if (and only if):
1) they are in the folders
2) The name of the file matches, using the correct underscore-to-titlecase conversion when writing your Ruby class names. Put another way, your file names must be in underscores (and lowercase), and your Ruby classes that each file defines must match exactly (in titlecase) the name of its file.
3) When a file appears in a subfolder, which is encouraged, you must namespace it –– the folder’s name (or namespace) is titlecased and prepended to the class name with
Those 3 rules are key. If you get them, you will master the the Rails autoload.
Rails has all kinds of reasons why you would want to create sub folders INSIDE of other folders. For example, let’s say you have a polymorphic set of Products. That is, you have a Product object with a type column that Rails will use to instantiate the objects.
A Basic Polymorphic Example
class Product < ApplicationRecord
class Shirt < Product
class Purse < Product
In the type column, you will see the name of the subclass directly. I will start by making a new Purse called “Little Clutch”
2.6.4 :004 > Purse.create(name: “Little Clutch”)
(0.2ms) begin transaction
Purse Create (2.0ms) INSERT INTO “products” (“name”, “type”, “created_at”, “updated_at”) VALUES (?, ?, ?, ?) [[“name”, “Little Clutch”], [“type”, “Purse”], [“created_at”, “2020-05-13 16:55:49.132712”], [“updated_at”, “2020-05-13 16:55:49.132712”]]
(2.0ms) commit transaction
=> #<Purse id: 1, name: “Little Clutch”, type: “Purse”, created_at: “2020-05-13 16:55:49”, updated_at: “2020-05-13 16:55:49”>
Then, I will create a Shirt called “Button down”
2.6.4 :005 > Shirt.create(name: “Button-down”)
(0.1ms) begin transaction
Shirt Create (0.6ms) INSERT INTO “products” (“name”, “type”, “created_at”, “updated_at”) VALUES (?, ?, ?, ?) [[“name”, “Button-down”], [“type”, “Shirt”], [“created_at”, “2020-05-13 16:56:05.042379”], [“updated_at”, “2020-05-13 16:56:05.042379”]]
(1.0ms) commit transaction
=> #<Shirt id: 2, name: “Button-down”, type: “Shirt”, created_at: “2020-05-13 16:56:05”, updated_at: “2020-05-13 16:56:05”>
In the example above, the three Ruby files (Product, Shirt, Purse) all appear in the root of the models/ folder
Polymorphic Autoload Example
Now let’s say we have many products and we want to move them into a sub folder called
We’ll want to do this with a little changes to our class objects. Here’s what our new files & folders will look like:
Notice we did some things here: One, the superclass
Product (was product.rb) has been renamed to products/base.rb
The class names now have namespaces— that’s because they are in the
products/ folder. You must always match the folder name to the namespace, but you will titleize the namespace and keep the folder names lowercase.
So our new Purse becomes
class Producs::Purse < Products::Base
And now, our Shirt becomes
class Products::Shirt < Products::Base
One last thing, in our Products::Base we’ll need to set the table name:
class Products::Base < ApplicationRecord
self.table_name = 'products'
Now, Rails knows how to magically load your files. Never do anything else– like put non-namespaced files into subfolders. That is a Very Bad Thing and Very Bad Things will happen to you if you do.
Remember, Rails will magically load all of your objects in models/ controllers/ but only when the name of the object matches exactly— including the namespace to it titleized form— with the name of your Ruby class.THE RAILS COACH
EXAMPLE APP FOR THIS POST CAN BE FOUND AT