Validations & Callbacks

Bad data is the enemy of every app. Rails validations let you declare the rules your records must satisfy, and callbacks let you hook into a record's lifecycle to normalise or react to changes.

Learn Validations & Callbacks in our free Ruby course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

By the end of this lesson you'll validate presence, uniqueness, length, and format, read errors, check valid?, and use callbacks like before_save and after_create.

What You'll Learn in This Lesson

1️⃣ Declaring Validations

Put validates calls in the model. Common rules include presence , uniqueness , length , format , and numericality . If any fail, save returns false and the errors explain why.

2️⃣ Lifecycle Callbacks

Callbacks fire at points in a record's life. before_validation and before_save run on every save; after_create runs only once, after a new record is inserted. Use them to normalise or derive data.

Your turn. Finish the validations on a Product model so name, sku, and price are all checked.

Validate a Signup and add a before_save callback that downcases the email before it is stored.

📋 Quick Reference — Validations & Callbacks

Practice quiz

Which validation ensures a column is not blank?

  • validates :name, length: true
  • validates :name, presence: true
  • validates :name, required: true
  • validates :name, not_null: true

Answer: validates :name, presence: true. presence: true rejects nil and blank values.

What does validates :email, uniqueness: true enforce?

  • The email is formatted correctly
  • No two records share the same email value
  • The email is present
  • The email is lowercase

Answer: No two records share the same email value. uniqueness: true rejects a record whose value already exists for that attribute.

Which method returns true only when all validations pass?

  • validate!
  • errors?
  • check
  • valid?

Answer: valid?. valid? runs validations and returns true if there are no errors.

After a failed save, where are the human-readable messages?

  • record.warnings
  • record.errors.full_messages
  • record.messages
  • record.invalid

Answer: record.errors.full_messages. errors.full_messages holds the readable list after validation fails.

Which validation limits a string to a maximum of 140 characters?

  • validates :body, max: 140
  • validates :body, size: 140
  • validates :body, limit: 140
  • validates :body, length: { maximum: 140 }

Answer: validates :body, length: { maximum: 140 }. length: { maximum: 140 } caps the length; minimum and is are also available.

Which callback runs just before a record is written on both create and update?

  • after_create
  • before_destroy
  • before_save
  • after_find

Answer: before_save. before_save runs prior to writing, for both new and existing records.

Which callback runs only after a brand-new record is first inserted?

  • after_create
  • before_save
  • after_save
  • before_validation

Answer: after_create. after_create runs once, after the initial INSERT of a new record.

What does save (without a bang) return when validation fails?

  • It raises an exception
  • It returns false
  • It returns nil and retries
  • It returns the errors array

Answer: It returns false. save returns false on validation failure; save! raises instead.

Which validation checks a value matches a regular expression?

  • validates :code, pattern: /.../
  • validates :code, regex: /.../
  • validates :code, format: { with: /.../ }
  • validates :code, match: /.../

Answer: validates :code, format: { with: /.../ }. format: { with: /regex/ } validates against a pattern.

How can you scope uniqueness so an email is unique per account?

  • uniqueness: { scope: :account_id }
  • uniqueness: :account_id
  • unique_within: :account
  • uniqueness: { per: :account }

Answer: uniqueness: { scope: :account_id }. uniqueness: { scope: :account_id } makes the value unique within each account.