Skip to content

Instantly share code, notes, and snippets.

@ashleymason
Last active August 13, 2020 20:09
Show Gist options
  • Save ashleymason/1acaee65d87ea757bb0d35d6ef253ef8 to your computer and use it in GitHub Desktop.
Save ashleymason/1acaee65d87ea757bb0d35d6ef253ef8 to your computer and use it in GitHub Desktop.
Model-Level Validations vs. Database Constraint

Model-Level Validations vs. Database Constraint

let's start with the TL;DR

  • what's better? database constraints or model validation?

    • no easy answer -- it depends on your problem
    • try to remember:
      • database constraints prevent bad data from being written
      • model validations allow for limitless specificity and quick pivots

    why not both?

SQL constraints:

  • NOT NULL

  • UNIQUE

  • INDEX

  • PRIMARY KEY - uniquely identifies each row in the current table (ie, UNIQUE + NOT NULL)

  • FOREIGN KEY - uniquely identifies a row / record in another table

  CREATE TABLE Orders (
      PRIMARY KEY (OrderID),
      FOREIGN KEY (PersonID) REFERENCES Persons(PersonID)
    );
  • CHECK - ensures that all values satisfy a specific condition
  CREATE TABLE Persons (
      ID int NOT NULL,
      Age int,
      CHECK (Age>=18)
    );
  • DEFAULT - sets default value when no value is specified
  CREATE TABLE Persons (
    ID int NOT NULL,
    City varchar(255) DEFAULT 'Sandnes'
  );

Rails Validation Helpers

Baked-In Validations

  • presence - validates that the specified attributes are not empty. It uses the 'blank?'' method

  • absence - validates that the specified attributes are absent. It uses the 'present?'' method. y tho?

  • uniqueness - validates that the attribute's value is unique right before the object gets saved

    • it does not create a uniqueness constraint in the database, so it may happen that two different database connections create two records with the same value for a column that you intend to be unique
  • validates_associated - use this helper when your model has associations with other models and they also need to be validated. When you try to save your object, "valid?" will be called upon each one of the associated objects

  • acceptance - validates that a checkbox on the user interface was checked when a form was submitted

class Person < ApplicationRecord
  validates :terms_of_service, acceptance: { message: 'must be abided' }
end
  • confirmation - use this helper when you have two text fields that should receive exactly the same content. For example, you may want to confirm an email address or a password

Build-Your-Own Validations

    • length - validates the length of the attributes' values
    • minimum
    • maximum
    • in a range
    • is exactly X
  • numericality - validates that your attributes have only numeric values. By default, it will match an optional sign followed by an integral or floating point number

    • only_integer
    • greater_than
    • greater_than_or_equal
    • equal_to
    • less_than
    • other_than
    • even
    • odd
  • format - validates the attributes' values by testing whether they match a given regular expression

class Product < ApplicationRecord
  validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/,
    message: "only allows letters" }
end
  • inclusion / exclusion - validates that the attributes' values are (not) included in a given set. In fact, this set can be any enumerable object
class Coffee < ApplicationRecord

validates :size, inclusion: { in: %w(small medium large),
  message: "%{value} is not a valid size" }
end
  • validates_with - passes the record to a separate class for validation
    • Campaigns::DestinationPageValidator
    • Campaigns::HasRequiredCustomImagesValidator
    • Campaigns::TargetingAudienceValidator
    • AccountOrGuestSessionIdValidator
    • AdConfigValidator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment