Model Structure Done Right

March 2, 2021 at 8:31 PM
codinggaming

I have been writing Ruby on Rails apps for almost a decade now and I've come to notice that my speed of development inversely scales with how many decisions I have to make.

A lot of these decisions come down to lack of structure. But reaching the point where you're comfortable with the final design really is a good feeling.

Here are my opinionated best practices for constructing ActiveRecord models:

class Post < ApplicationRecord

  # ==================================================
  # Module & Concern Includes
  # ==================================================

  include ActsAsStateMachine
  include Commentable

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

  ACTIVE_STATES = %i[published]
  INACTIVE_STATES = %i[draft discarded]

  # ==================================================
  # Default Scope
  # ==================================================

  default_scope { kept }

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

  before_create :private_method

  # ==================================================
  # Non-persistant Attributes
  # ==================================================

  attribute :attr1, default: false
  attr_accessor :attr2

  # ==================================================
  # Associations
  # ==================================================

  belongs_to :author
  has_one :latest_edit, -> { order() }, class_name: 'Edit'
  has_many :tags
  accepts_nested_attributes_for :tags

  # ==================================================
  # Attachments
  # ==================================================

  has_one_attached :cover
  has_many_attached :previews

  # ==================================================
  # Additional Attribute Helpers
  # ==================================================

  monetize :price_cents
  translates :title

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

  validates :title, presence: true, length: { minimum: 10, maximum: 80 }

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

  scope :active, -> { where(state: ACTIVE_STATES) }
  scope :inactive, -> { where(state: INACTIVE_STATES) }

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

  def current_catalogue_programming(country:)
    catalogue_programmings.available(country: country).first
  end

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

  def self.average_rating
    average(:rating)
  end

  # ==================================================
  # Private Methods
  # ==================================================

  private

  def private_method
  end

end