Models

Role of Models

A model is an abstraction on top of data. It should only be responsible of understanding its own data structure and logic.
A model is also part of a collection. Everything related in doing specfic queries to the collection should be in the model. If the query is too complex, it should be a Query Object instead.

Location

  • app/models/
  • Should have no prefix and no suffix.

Usage

  • A model can be called from everywhere in the application.
  • Try to not call them directly in the Views.

Naming

The model has the name of the SQL table in singular and Capitalzed. Examples:

  • User
  • Admin
  • Post
  • JobOffer
  • Company

Structure

A model can handle different behaviors and include plugins. This is the recommended order of declaration in the model class:

  • include
  • concerns
  • relations: belongs_to, has_many, has_one
  • constantes
  • validation: If there is no specific Predicates.
  • callbacks
  • plugins
  • scopes
  • class methods: custom queries (where)
  • instance methods
  • private methods

Things to avoid

A model should be as standalone as possible. These things should be avoided in a model and moved in a better place like Services, Query Objects, Decorators, and Model Concerns:

  • Formating: Decorators
  • Calling external API's: Services
  • Complex logic involving relations: Query Objects
  • Callbacks: Use them if it's really necessary (like generating slugs after create or update).

Code

class User < ApplicationRecord
  include SecurePasswordConcern

  belongs_to :company
  has_many :projects

  MIN_AGE = 16

  validates :first_name, presence: true
  validates :email, uniqueness: true

  after_create :generate_api_token
  after_create :generate_slug

  geocode_by :address

  scope :actives, -> { where("last_signd_in_at >= ?", 1.day.ago) }
  scope :young, -> { where("birthdate >= ?", MIN_AGE.years.ago) }

  class << self
    def remove_inactives
      where("last_signd_in_at < ?", 1.year.ago).destroy_all
    end
  end

  def address
    "#{street}, #{postcode} #{city}, #{country}"
  end

  def active?
    self.last_signd_in_at < 1.day.ago
  end

  private
  def generate_api_token
    self.api_token = SecureRandom.hex(10)
    self.save
  end

  def generate_slug
    self.slug = "#{self.first_name}-#{self.last_name}".parametize
    self.save
  end
end

results matching ""

    No results matching ""