Structuring Models

Published by Aaron Price on March 5, 2016

When you first start building an application, it can be easy to add code to the models as you need it. However, over time, the model becomes a bit messy. This problem is further compounded when you're working in a team environment.

I've even run into cases where dependencies become a problem because of the order of the code.

Consider the following User model:


class User < ActiveRecord::Base

  has_many :posts
  belongs_to :tenant

  validates :name, presence: true
  validates :email, presence: true, format: { with: /\A[^@\s][email protected]([^@\s]+\.)+[^@\s]+\z/ }

  attr_sanitizable :name, with: [:strip]
  attr_sanitizable :email, with: [:strip, :downcase]

  USER_TYPES = ["Employee", "Admin", "Contractor"]
  validates :type, presence: true, inclusion: { in: USER_TYPES }

  attr_accessor :image_changed

  scope :active, -> { where("last_login_at > ?", 1.month.ago) }

  before_validation :set_defaults

  def set_defaults
    self.uuid ||= UUID.new.generate
  end
end

I've found it useful to use a template for models which defines a structure of where different components belong. This helps me to keep models structured and makes it easy to find what I'm looking for at any given time.

Here's that same User model after I've applied the template:


class User < ActiveRecord::Base

  # == Constants ============================================================

  USER_TYPES = ["Employee", "Admin", "Contractor"]

  # == Attributes ===========================================================

  attr_accessor :image_changed

  # == Extensions ===========================================================

  attr_sanitizable :name, with: [:strip]
  attr_sanitizable :email, with: [:strip, :downcase]

  # == Relationships ========================================================

  has_many :posts
  belongs_to :tenant

  # == Validations ==========================================================

  validates :name, presence: true
  validates :type, presence: true,  inclusion: { in: USER_TYPES }
  validates :email, presence: true, format: { with: /\A[^@\s][email protected]([^@\s]+\.)+[^@\s]+\z/ }

  # == Scopes ===============================================================

  scope :active, -> { where("last_login_at > ?", 1.month.ago) }

  # == Callbacks ============================================================

  before_validation :set_defaults

  # == Class Methods ========================================================

  # == Instance Methods =====================================================

  def set_defaults
    self.uuid ||= UUID.new.generate
  end
end

It's very easy to follow, and it's always clear where code belongs.

Here's the template for you to use:


  # == Constants ============================================================

  # == Attributes ===========================================================

  # == Extensions ===========================================================

  # == Relationships ========================================================

  # == Validations ==========================================================

  # == Scopes ===============================================================

  # == Callbacks ============================================================

  # == Class Methods ========================================================

  # == Instance Methods =====================================================

If you use textmate or sublime text, you can add the above template as a snippet that you apply to any new model.

About me...

My name is Aaron Price. I'm a ruby developer based in Toronto and I'm passionate about simplicity.

Feel free to reach out using the following links: