Rails' naming convention, and where this app breaks it

Free preview 3 min to read

One rule, followed without thinking about it

Every model these courses have touched, like Catalog::Course, Enrollment::Enrollment and Identity::User, finds its table without anyone writing mapping code, most of the time. Rails' rule is to take the class name, demodulize it (drop any Module:: prefix), underscore it and pluralize it. Article becomes articles. That's the whole convention, and it's why no earlier course had to explain it: it works quietly whenever the class name and the table name already agree.

When they stop agreeing

This app's Catalog module defines something most namespaces never bother with:

# app/models/catalog.rb
module Catalog
  def self.table_name_prefix
    "catalog_"
  end
end

That one method changes the convention's output for every model under Catalog::. A throwaway class with no explicit table name:

class Catalog::ScratchNoOverride < ApplicationRecord
end

Catalog::ScratchNoOverride.table_name
# => "catalog_scratch_no_overrides"

The same three steps, demodulize, underscore and pluralize, and then catalog_ in front because the surrounding module asked for it. On its own, Catalog::Course would resolve to catalog_courses. The actual table is courses.

The line that bridges the gap

The first line inside Catalog::Course:

# app/models/catalog/course.rb
class Course < ApplicationRecord
  self.table_name = "courses"
end

With that one assignment, the convention's output stops mattering for this class. self.table_name = doesn't adjust the convention; it replaces the result, so Rails never computes catalog_courses for a model that's told which table to use.

Why this matters beyond one model

It isn't a one-off fix for Course. Nearly every model in the Catalog::, Enrollment:: and Partners:: namespaces carries its own self.table_name line: Catalog::Lesson → "lessons", Enrollment::Enrollment → "enrollments", Partners::Partner → "partners". The lines aren't decorative. Without them, each of those classes would look for a prefixed table that doesn't exist, because its namespace defines a table_name_prefix. That's the problem self.table_name solves. The one model that goes without it, Community::Comment, is lesson 2's example.

Key takeaways

  • Rails' naming convention: demodulize the class name, underscore it, pluralize it. Article → articles, with no code written, as long as nothing changes the inputs.
  • This app's Catalog module defines self.table_name_prefix returning "catalog_", so a model under Catalog:: with no override gets the prefix: catalog_scratch_no_overrides.
  • That makes the convention's output for Catalog::Course catalog_courses, while the actual table is courses.
  • self.table_name = "courses", the first line of Catalog::Course, replaces the computed result instead of adjusting it, and almost every model in the prefixed namespaces carries the same kind of line for the same reason.
Lesson 1 of 7 · free

Keep going with lesson 2

table_name_prefix: the namespace's default

The table_name_prefix method on namespace modules, and how Community::Comment resolves to community_comments through it.

A free account also gives you the quizzes, your progress and notes, and the discussion.

Type to start searching...