142 Validations [1.5d]

Updated . Posted . Visible to the public.

Validations keep invalid data out of your database. This lesson covers Rails' built-in validations, how to test them, and how to show helpful error messages in your forms.

Important

Work on this lesson in teacher mode.

Learning goals

  • You can validate records with Rails' built-in validations and know where to look up the rest.
  • You can explain why a uniqueness validation, unlike other validations, needs a unique index in the database, and add both.
  • You can explain when validations run, how saving behaves on an invalid record, and how to inspect the reasons.
  • You can write a custom validation for a rule that spans several attributes.
  • You can test a single validation in isolation, e.g. with Shoulda matchers.
  • You can show validation errors next to the fields they belong to, styled so the invalid field stands out.
  • You can give feedback after a form was saved or rejected, e.g. with flash messages.

Resources

Read what's new to you, skim what's familiar, skip what you already master. Stop when you can meet the learning goals.

Your agent can also generate an overview, a tutorial or an explanation for anything here, tailored to what you already know. Just ask.

Exercises

Basic validations

Make the following changes to your MovieDB:

  • Make sure your MovieDB models have validations for all required fields.
  • Two movies must not have the same title and release year. Validate it, and back it with a unique index.
  • Make sure you have specs for all your validations in MovieDB.
  • Use Shoulda matchers where you think they improve the readability of your code.

Note

Most validations only look at the record being saved, so their result can't change behind your back. uniqueness is different: it checks other rows with a SELECT before saving, and two requests saving at the same time can both pass that check. That's why a uniqueness validation needs a unique index in the database (add_index :movies, [:title, :release_year], unique: true). The index makes the database reject the duplicate, and the validation still shows a friendly error message in the common case.

Tip

Shoulda's examples use RSpec's one-liner syntax:

describe Movie do
  it { is_expected.to validate_presence_of(:title) }
end

This is short for:

describe Movie do
  it 'validates the presence of title' do
    movie = Movie.new
    expect(movie).to validate_presence_of(:title)
  end
end

subject is the object under test. For describe Movie it's Movie.new by default. is_expected is short for expect(subject). Without a description, it generates one from the matcher.

Working with error messages

Understand how to use the #errors method Show archive.org snapshot to inspect the reasons why a record is invalid.

Make the following changes to your MovieDB:

  • There is no longer a full list of error messages at the top of each failed form.

  • When a form could not be saved, only the fields with errors show their respective error messages.

    Your forms should be triples of label, input and error message:

    Title
    [_____________________]
    Title must not be blank
    
    Release year
    [____-5]
    Release year must be a positive number
    
  • If a field has more than one error, only show the first error.

  • A web app has a lot of fields, and each must be able to display an error message. Make it easy for a form view to display the error message for a given record and field. Remove as much code from the view as possible.

    Tip

    You will be writing a ton of forms in your career. Showing the error for a given record and attribute should be maximally comfortable for your views β€” nudge yourself toward a helper with a nice API, like error_message(@movie, :title).

  • Style your form so that when a field is invalid, the label and error message is colored red. In addition, an invalid field control should have a red border.

    Tip

    Rails adds an extra element around invalid inputs to help with styling. Inspect an invalid field in your browser to see how it works.

  • Add support for a positive and negative flash message Show archive.org snapshot in your application layout. When a form could be saved successfully, show a flash like "Movie saved". When a form is re-rendered due to a validation error, show a flash like "Could not save".

    Tip

    Unlike @variables set by a controller, flash messages persist to the next request. This is to support the case of setting a flash and then redirect.

    If you have trouble with flash messages appearing longer than they should, you can set them to flash.now or clear all flash messages after displaying them by using flash.clear.

Custom validations

Add the following feature to your MovieBD:

  • The release year field of Movies should always be a number. It can also be missing (nil).
  • Movies have a film type. This is a string that is either "black_and_white" or "color".
  • The default film type is "color".
  • In the movie form we can switch between black and white and color movies using a <select>.
  • Add a validation that ensures that release_year >= 1895 for black and white movies and release_year >= 1917 for color movies.

Add tests for your validation. Make sure you have a test for each case.

Hint

Profile picture of Henning Koch
Henning Koch
Last edit
Michael LeimstΓ€dtner
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra Curriculum (2021-10-11 13:09)