Back
Chapters

Order of items on Active Record models

Search icon
Search Book
⌘K

In this chapter we are going to discuss how Active Record models should be structured.

Let's start by looking into the unordered definition of the User model, which will work, but has the potential to cause a lot of harm and debugging issues in the future.

Note that the following is an example of how we shouldn't structure our model:

1# frozen_string_literal: true
2
3class User < ApplicationRecord
4
5  def to_lowercase
6    email.downcase
7  end
8
9  before_save :to_lowercase
10
11  VALID_EMAIL_REGEX = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
12  validates :email,
13    presence: true,
14    length: { maximum: 255 },
15    format: { with: VALID_EMAIL_REGEX },
16    uniqueness: { case_sensitive: false }
17
18  validates :first_name, presence: true, length: {maximum: 50}
19  validates :last_name, presence: true, length: {maximum: 50}
20end

Items should be presented in an order

Above code works but the Rails community has agreed upon certain order in which items should be presented. And the order goes something like this:

  • default_scope
  • constants
  • attr_*
  • enum
  • associations
  • validations
  • callbacks
  • other macros (like devise's, has_secure_password) should be placed after the callbacks
  • public methods
  • private methods

The RuboCop Rails style guide is a good reference for this.

Now we can rearrange the above to look like this:

1# frozen_string_literal: true
2
3class User < ApplicationRecord
4  VALID_EMAIL_REGEX = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
5  validates :email,
6    presence: true,
7    uniqueness: { case_sensitive: false }
8    length: { maximum: 255 },
9    format: { with: VALID_EMAIL_REGEX },
10
11  validates :first_name, presence: true, length: {maximum: 50}
12  validates :last_name, presence: true, length: {maximum: 50}
13
14  before_save :to_lowercase
15
16  private
17
18    def to_lowercase
19      email.downcase
20    end
21end

Let's take a look at the User model in our Granite application. If you recall we updated the User model in Adding comments to a task chapter to:

1# frozen_string_literal: true
2
3class User < ApplicationRecord
4  VALID_EMAIL_REGEX = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
5
6  has_many :comments, dependent: :destroy
7  has_many :tasks, dependent: :destroy, foreign_key: :user_id
8
9  validates :name, presence: true, length: { maximum: 35 }
10  validates :email,
11    presence: true,
12    uniqueness: { case_sensitive: false },
13    length: { maximum: 50 },
14    format: { with: VALID_EMAIL_REGEX }
15  validates :password,
16    presence: true,
17    confirmation: true,
18    length: { minimum: 6 }
19  validates :password_confirmation, presence: true, on: :create
20
21  before_save :to_lowercase
22
23  has_secure_password
24  has_secure_token :authentication_token
25
26  private
27
28    def to_lowercase
29      email.downcase!
30    end
31end

We can see that all the items are in correct order inside the User model.

Ideally, we should go through all our models and make sure that the ordering is taken care of. But for the time being let's focus on creating our application.

In the upcoming chapters let's try to add Rubocop rules which can do this job or at least warn us, when ordering is not correct.

After going through the User model and refactoring it (if required), commit the changes:

1git add -A
2git commit -m "Fixed order of items in Active Record models"