DEV Community

arbarrington
arbarrington

Posted on • Updated on

Rails Validation

validates :name, presence: true
validates :name, length: { minimum: 2 }
validates :email, uniqueness: true
validates :not_a_robot, acceptance: true, message: "Humans only!"
validates :year, numericality: {
    greater_than_or_equal_to: 1888,
    less_than_or_equal_to: Date.today.year
  }
Enter fullscreen mode Exit fullscreen mode
def create
  person = Person.create!(person_params)
  render json: person, status: :created
rescue ActiveRecord::RecordInvalid => invalid
  render json: { errors: invalid.record.errors.full_messages }, status: :unprocessable_entity
end
Enter fullscreen mode Exit fullscreen mode

Database activity triggers validation. An Active Record model instantiated with #new will not be validated, because no attempt to write to the database was made. Validations won't run unless you call a method that actually hits the DB, like #save.

The only way to trigger validation without touching the database is to call the #valid? method.

Custom Validation

class Person
  validate :must_have_flatiron_email

  def must_have_flatiron_email
    unless email.match?(/flatironschool.com/)
      errors.add(:email, "We're only allowed to have people who work for the company in the database!")
    end
  end
end
Enter fullscreen mode Exit fullscreen mode
validate :clickbait?

  CLICKBAIT_PATTERNS = [
    /Won't Believe/i,
    /Secret/i,
    /Top \d/i,
    /Guess/i
  ]

  def clickbait?
    if CLICKBAIT_PATTERNS.none? { |pat| pat.match title }
      errors.add(:title, "must be clickbait")
    end
  end

Enter fullscreen mode Exit fullscreen mode

We can clean up this controller action by handling the ActiveRecord::RecordInvalid exception class along with create! or update!:

def create
  bird = Bird.create!(bird_params)
  render json: bird, status: :created
rescue ActiveRecord::RecordInvalid => invalid
  render json: { errors: invalid.record.errors }, status: :unprocessable_entity
end
Enter fullscreen mode Exit fullscreen mode

In the rescue block, the invalid variable is an instance of the exception itself. From that invalid variable, we can access the actual Active Record instance with the record method, where we can retrieve its errors.

def render_not_found_response(exception)
render json: { error: "#{exception.model} not found" }, status: :not_found
end

Top comments (0)