/

TIL: :restrict_with_error

Jul 6, 2026

I’ve been using Rails for 15+ years and I still find useful stuff that I didn’t know about.

This week, my discovery is the restrict_with_error option for the has_one and has_many :dependent setting.

Example

I developed a tiny workout tracking application which has an Exercise model. This is stuff like “Squat” or “Deadlift”. Every workout session consists of multiple WorkoutExercise objects, which record a concrete session of that Exercise being used in a workout.

class WorkoutExercise < ApplicationRecord
  belongs_to :workout

  has_many :sets # and sets have reps
end

The question is what happens when I decide to delete an Exercise. Previously, I would manually write a before_destroy callback to check if an Exercise has been used in any workouts and prevent it from being deleted. Turns out this has been baked into the has_one and has_many methods ever since Rails 4 in 2013:

class Exercise
  has_many :workout_exercises, dependent: :restrict_with_error
  # ...
end

With this, attempting to delete an exercise that is already referenced by exiting Workouts shows a nice error on the exercise object:

e = Exercise.find(1)
# => #<Exercise:0x0000000109d4ded8>

e.name
# => "Squat"

e.destroy
# => false

e.errors
# => #<ActiveModel::Errors [#<ActiveModel::Error attribute=base, type=restrict_dependent_destroy.has_many, options={:record=>"workout exercises"}>]>

e.errors.full_messages
# => ["Cannot delete record because dependent workout exercises exist"]

This is much nicer and elegant than having to roll a custom validation.

There’s also :restrict_with_exception, which raises an exception instead of adding validation errors to the object.

Discuss this post on Twitter →
[ shameless plug ]
Psst. Check out my latest project, Stonksfolio, if you need an awesome portfolio tracker!