Git Product home page Git Product logo

validations-with-form_for-rails's Introduction

Validations with form_for

Now that we know Rails automatically performs validations defined on models, let's use this information to easily display validation errors to the user.

Objectives

After this lesson, you'll be able to...

  • use form_for to display a form with Validations
  • print out full error messages above the form

The differences between form_for and form_tag

This step will make heavy usage of form_for, the high-powered alternative to form_tag. The biggest difference between these two helpers is that form_for creates a form specifically for a model object. form_for is full of convenient features.

In the example below, @post is the model object that needs a form. form_for automatically performs a route lookup to find the right URL for post.

form_for takes a block. It passes an instance of FormBuilder as a parameter to the block, which is what f is below.

A basic implementation looks like this:

<!-- app/views/posts/edit.html.erb //-->

<%= form_for @post do |f| %>
  <%= f.text_field :title %>
  <%= f.text_area :content %>
  <%= f.submit %>
<% end %>

This creates the HTML:

<form class="edit_post" id="edit_post" action="/posts/1" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input type="hidden" name="_method" value="patch" />
  <input type="hidden" name="authenticity_token" value="nRPP2OqVKB00/Cr+8EvHfYrb5sAkZRtr8f6dzBaJAI+cMceR0fUatcLWd4zdwYCpojW2J3QLK6uyBKeFAgZvmw==" />
  <input type="text" name="post[title]" id="post_title" value="Existing Post Title"/>
  <textarea name="post[content]" id="post_content">Existing Post Content</textarea>
  <input type="submit" name="commit" value="Update Post" />
</form>

Here's what we would need to do with form_tag to generate the exact same HTML:

<!-- app/views/posts/new.html.erb //-->

<%= form_tag post_path(@post), method: "patch", name: "edit_post", id: "edit_post" do %>
  <%= text_field_tag "post[title]", @post.title %>
  <%= text_area "post[content]", @post.content %>
  <%= submit_tag "Update Post" %>
<% end %>

form_tag doesn't know what action we're going to use it for, because it has no model object to check. form_for knows that an empty, unsaved model object needs a new form and a populated object needs an edit form. This means we get to skip all of these steps:

  1. Setting the name and id of the <form> element.
  2. Setting the method to patch on edits.
  3. Setting the text of the <submit> element.
  4. Specifying the root parameter name (post[whatever]) for every field.
  5. Choosing the attribute (@post.whatever) to fill for every field.

Nifty!

Using form_for to generate empty forms

To wire up an empty form in our new view, we need to create a blank object:

# app/controllers/posts_controller.rb

  def new
    @post = Post.new
  end

Here's our usual vanilla create action:

# app/controllers/posts_controller.rb

  def create
    @post = Post.create(post_params)

    redirect_to post_path(@post)
  end

We still have to solve the dual problem of what to do when there's no valid model object to redirect to, and how to hold on to our error messages while re-rendering the same form.

Re-Rendering With Errors

Remember from a few lessons ago how CRUD methods return false when validation fails? We can use that to our advantage here and branch our actions based on the result:

# app/controllers/posts_controller.rb

  def create
    @post = Post.new(post_params)

    if @post.save
      redirect post_path(@post)
    else
      render :new
    end
  end

Full Messages with Prepopulated Fields

Because of form_for, Rails will automatically prepopulate the new form with the values the user entered on the previous page.

To get some extra verbosity, we can add the snippet from the previous lesson to the top of the form:

<!-- app/views/posts/new.html.erb //-->

<% if @post.errors.any? %>
  <div id="error_explanation">
    <h2>
      <%= pluralize(@post.errors.count, "error") %>
      prohibited this post from being saved:
    </h2>

    <ul>
    <% @post.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

More Freebies: field_with_errors

Let's look at another nice feature of FormBuilder. Here's our form_for code again:

<!-- app/views/posts/edit.html.erb //-->

<%= form_for @post do |f| %>
  <%= f.text_field :title %>
  <%= f.text_area :content %>
  <%= f.submit %>
<% end %>

The text_field call generates this tag:

<input type="text" name="post[title]" id="post_title" value="Existing Post Title"/>

Not only will FormBuilder pre-fill an existing Post object's data, it will also wrap the tag in a div with an error class if the field has failed validation(s):

<div class="field_with_errors">
  <input type="text" name="post[title]" id="post_title" value="Existing Post Title"/>
</div>

This can also result in some unexpected styling changes because <div> is a block tag (which takes up the entire width of its container) while <input> is an inline tag. If your layout suddenly gets messed up when a field has errors, this is probably why.

Recap

form_for gives us a lot of power!

Our challenge as developers is to keep track of the different layers of magic that make this tool so convenient. The old adage is true: we're responsible for understanding not only how to use form_for but also why it works. Otherwise, we'll be completely lost as soon as a sufficiently unusual edge case appears.

When in doubt, read the HTML. Get used to hitting the "View Source" and "Open Inspector" hotkeys in your browser (Ctrl-u and Ctrl-Shift-i on Chrome Windows; Option-Command-u and Option-Command-i on Chrome Mac), and remember that most browsers let you examine POST data in their developer network tools.

View Validations with `form_for` on Learn.co and start learning to code for free.

validations-with-form_for-rails's People

Contributors

annjohn avatar aviflombaum avatar bhollan avatar changemewtf avatar coltonstaab1 avatar franknowinski avatar jmburges avatar mendelb avatar ngevan avatar pletcher avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.