Forms in Rails: Processing & Editing Form Data

Free Ruby on Rails Tutorial

Dive deep into the Ruby on Rails tutorial, covering topics such as making the form work by defining the create method, making an edit form, optimizing your code, and more.

This exercise is excerpted from Noble Desktop’s past web development training materials. Noble Desktop now teaches JavaScript and the MERN Stack in our Full Stack Development Certificate. To learn current skills in web development, check out our coding bootcamps in NYC and live online.

Note: These materials are provided to give prospective students a sense of how we structure our class exercises and supplementary materials. During the course, you will get access to the accompanying class files, live instructor demonstrations, and hands-on instruction.

Topics covered in this Ruby on Rails tutorial:

Making the form work: defining a create method, Making an edit form, Optional bonus: DRYing up the code even more

Exercise Preview

preview rails forms processing

Full-Stack Web Development Certificate: Live & Hands-on, In NYC or Online, 0% Financing, 1-on-1 Mentoring, Free Retake, Job Prep. Named a Top Bootcamp by Forbes, Fortune, & Time Out. Noble Desktop. Learn More.

Exercise Overview

In the previous exercise we created a form, but it can’t submit the data yet. Something in the controller needs to be ready to receive the data from the form, process it, and create a new movie object based on that information. In Resourceful Routing that method is called Create.

  1. If you completed the previous exercises, you can skip the following sidebar. We recommend you finish the previous exercises before starting this one. If you haven’t finished them, do the following sidebar.

    If You Did Not Do the Previous Exercises (3A–4A)

    1. Close any files you may have open.
    2. Open the Finder and navigate to Class Files > yourname-Rails Class
    3. Open Terminal.
    4. Type cd and a single space (do NOT press Return yet).
    5. Drag the yourname-Rails Class folder from the Finder to the Terminal window and press ENTER.
    6. Run rm -rf flix to delete your copy of the Flix site.
    7. Run git clone https://bitbucket.org/noble-desktop/flix.git to copy the Flix git repository.
    8. Type cd flix to enter the new directory.
    9. Type git checkout 4A to bring the site up to the end of the previous exercise.
    10. Run bundle to install any necessary gems.
    11. Run yarn install --check-files to install JavaScript dependencies.

Getting Started

  1. Open the Finder and navigate to Class Files > yourname-Rails Class

  2. Open Terminal.

  3. Type cd and a single space (do NOT press Return yet).

  4. Drag the flix folder from the Finder to the Terminal window.

  5. Make sure you’re in Terminal and hit Return to change into the new folder.

  6. Type the following to launch the server:

    rails server
    
  7. Open a browser and navigate to localhost:3000 just to check that everything is up and running. You should see the Flix website.

  8. We suggest opening the entire flix folder in your code editor if it allows you to (like Sublime Text does).

Making the Form Work: Defining a Create Method

  1. In your code editor open flix > app > controllers > movies_controller.rb

  2. Create a new method right before the final end in the document as follows:

       def create
    
       end
    end
    

    Inside this create method we will receive and process what are called the parameters from this form. Rails receives and processes form permissions in a hash called params. An important security feature in Rails called strong parameters requires us to white-list those parameters we expect to receive through each form. This feature is a safeguard against the injection of additional parameters which might allow unauthorized users to modify content in an inappropriate way.

    The upshot of this security method is that controllers are responsible for declaring which parameters they want to receive with a function called params.permit followed by a list of expected parameters.

  3. Add the following bold code:

    def create
       movie_params = params.require(:movie).permit()
    end
    
  4. Complete the list of expected parameters by adding the following bold code (on a single line):

    movie_params = params.require(:movie).permit(:title, :description, :has_subtitles,
    :placement, :mpaa_rating, :release_date, :ticket_price, :runtime, :poster_image
    )

    Take a moment to double-check your work. That was tedious to type out, but it will provide additional security. Now let’s create the new movie object.

  5. After the parameters line (some code omitted to save space), add the following bold code to create the new movie object:

    def create
       movie_params = params.require(:movie).permit(...)
       @movie = Movie.new(movie_params)
    end
    

    In order to program the creation of the new movie object from information sent from the form, all we had to do is set instance variable @movie equal to Movie.new and send the movie_params object directly into Movie.new, and we can count on Rails to do the rest for us.

  6. If we stopped at this point, a new movie would be created, but temporarily—we need to save the information in the database! Add the following bold code to the create method:

       @movie = Movie.new(movie_params)
       if @movie.save
          redirect_to @movie
       else
          render action: 'new'
       end
    end
    

    We want the user to know whether or not their movie was created successfully. This if/else statement you just wrote will either send them to the completed movie page or, if the movie creation fails, send them back to the new screen with the data they’ve already entered. If it succeeds, it will display a new movie page, but it would be nice to have a message on that page saying the movie was successfully created. Let’s add that.

  7. Save the file.

  8. Open flix > app > views > layouts > application.html.erb

  9. Around line 52 notice this piece of code:

    <% if flash[:alert] %>
       <div id="flash" class="alert"><%= flash[:alert] %></div>
    <% elsif flash[:notice] %>
       <div id="flash" class="notice"><%= flash[:notice] %></div>
    <% end %>
    

    We have coded this alert system in advance for you to save a little time. Thanks to some CSS classes, the notice will display a message with a green background, and the alert will display a message with a red background.

  10. Now we have to tell Rails to put a message into this notice. Switch back to movies_controller.rb

  11. Add the following bold code:

    if @movie.save
       redirect_to @movie, notice: 'Movie was created successfully.'
    else
    
  12. Save the file.

  13. Switch to the browser and go to localhost:3000/movies/new

  14. Let’s try adding a real movie through the form! We have a text file with the description, etc. typed up to save you some work. Switch to the Finder.

  15. Navigate into Class Files > yourname-Rails Class > flix snippets and double–click on gone_with_the_windows.txt to open it (it will probably open in TextEdit).

  16. Arrange your windows so gone_with_the_windows.txt and the browser window are side-by-side.

  17. Copy and paste all of the information from gone_with_the_windows.txt into the proper form fields. For the multiple-choice fields, set the Placement to In Theaters, MPAA Rating to PG, and Release Date to any future date as indicated in the text file.

  18. When done, click Create Movie.

    You should be directed to localhost:3000/movies/4 where you can see the new movie page for Gone With the Windows and a green banner at the top of the page alerting you to the successful creation of a new movie.

Making an Edit Form

The form is working great—but what if we need to edit an existing movie? The PR Department is demanding that we make two changes to the Text M for Murder page: the movie is rated R, not PG, and the description is inaccurate too—it’s about an ex-tennis star, not an ex-golfer.

Let’s make an edit form. We can use the existing create form as a starting point.

  1. Switch to movies_controller.rb in your code editor.

  2. Add the following edit method directly above the final end of the document, around line 36:

       def edit
          @movie = Movie.find(params[:id])
       end
    end
    
  3. Save the file.

  4. Open flix > app > views > movies > new.html.erb in your code editor.

  5. Choose File > Save As.

  6. Name the file edit.html.erb and make sure it’s in: flix > app > views > movies (it should be in that folder by default, but it’s always good to double-check).

  7. Find the header on the first line of the document:

    <h1>Add Movie</h1>
    
  8. Edit the line to read:

    <h1>Edit Movie</h1>
    

    We’ll also need to make a corresponding update method. (Just as the create method went with the new page, the update method goes with the edit page.)

  9. Save the file.

  10. Switch to movies_controller.rb

  11. Around line 40 add the following bold code:

       def update
    
       end
    end
    
  12. Copy the contents of the edit method above and paste the code in the update method as shown below:

    def update
       @movie = Movie.find(params[:id])
    end
    
  13. Find the following piece of code a little further up in the file (around line 27):

    movie_params = params.require(:movie).permit(:title, :description, :has_subtitles,
    :placement, :mpaa_rating, :release_date, :ticket_price, :runtime, :poster_image)

  14. Copy the code.

  15. Paste the code inside the update method:

    def update
       @movie = Movie.find(params[:id])
       movie_params = params.require(:movie).permit(...)
    end
    
  16. Add the following bold code to the update method:

       @movie = Movie.find(params[:id])
       movie_params = params.require(:movie).permit(...)
       if @movie.update(movie_params)
          redirect_to @movie, notice: 'Movie was successfully updated.'
       else
          render action: 'edit'
       end
    end
    
  17. Save the file.

  18. In a browser navigate to localhost:3000/movies/1/edit

  19. The edit form should be looking pretty good! In the Description text area, change ex-golfer to ex-tennis star.

  20. Change the MPAA Rating to R. (You may notice that the menu is currently empty, instead of showing the current rating. We’ll fix that in a moment.)

  21. Click Update Movie.

    You should be redirected to localhost:3000/movies/1 with a green banner at the top of the page: Movie was successfully updated.

    So all we had to do was copy and paste the existing form, tweak the heading, and thanks to Rails 4 form helper and the @movie instance variable, all the fields were automatically pre-populated for us with the existing movie’s information.

DRYing Up the Code with Partials

Although we got this done this quickly, the end result is kind of sloppy. We have the same form code in two different files, the new and edit pages. As new fields get added to the movies form (and we’ll be adding several!) we’ll have to remember to update both forms identically—no good!

A key principle in Rails is DRY (Don’t Repeat Yourself). Having code routines that do the same thing in multiple places—like we’re doing here with two identical forms—creates a lot of problems, maintenace issues, and bugs. Fortunately, Rails provides tons of helpful tools to keep your code DRY, and we’re going to use one called partials here.

A partial is like a sub-view that can be rendered from inside of other views. It’s not usually called by a controller directly. You can recognize the files easily because partials start with an underscore, like so: _partial.

  1. Switch to edit.html.erb in your code editor.

  2. Do a File > Save As.

  3. Save the new file as _form.html.erb (don’t forget the underscore indicating it’s a partial!) and make sure it’s saved in flix > app > views > movies (it should be there by default).

  4. Delete the heading on the first line. (This will need to change depending on whether you are editing or creating a new movie.)

  5. Save the file.

  6. Re-open edit.html.erb (it’s in flix > app > views > movies).

  7. Delete everything except the first line (the heading).

  8. Add the following bold code:

    <h1>Edit Movie</h1>
    <%= render 'form' %>
    
  9. Save the file.

  10. Open new.html.erb (it’s in flix > app > views > movies).

  11. Delete everything except the first line (the heading).

  12. Add the following bold code:

    <h1>Add Movie</h1>
    <%= render 'form' %>
    
  13. Save the file.

  14. Both of these files now point to the same form so we’re reusing the code instead of repeating it. In a browser go to localhost:3000/movies/new and the form for creating movies should still be working and looking the same, even though the form is now being rendered as a partial.

  15. Navigate to localhost:3000/movies/4/edit/ and notice that the form is looking good on that page, too. Our code is DRY and the form is still working; all is good in the world. Except… if you look at the MPAA Rating field on the edit page, it is blank. It’s not remembering the info for this movie because we forgot to tell the options_for_select helper to do that. Let’s fix it now.

  16. Switch to _form.html.erb in your code editor.

  17. Find the following line of code, around line 24:

    <% mpaa_ratings = options_for_select ["G", "PG", "R", "NR"] %>
    
  18. Add the following bold code and don’t miss the comma!

    <% mpaa_ratings = options_for_select ["G", "PG", "R", "NR"], selected: @movie.mpaa_rating %>
    
  19. Save the file.

  20. Switch to the browser, reload localhost:3000/movies/4/edit and check to see that the bug has been fixed!

  21. Back in Terminal hit Ctrl–C to shut down the server.

Optional Bonus: DRYing Up the Code Even More

There’s a little more work we could do to DRY up the controller, because there are a few repeating pieces of code.

  1. Switch to movies_controller.rb in your code editor.

  2. Directly before the final end at the bottom, add the following bold private method:

          end
       end
    
       private
          def movie_params
       end
    end
    

    Private methods can only be called from within the controller itself. The methods we are going to put here are non-action (or helper) methods. It’s a best practice in Rails to make non-action methods private, to differentiate them from methods accessible via routes.

  3. A few lines up (in the update method around line 42) find this line of code:

    movie_params = params.require(:movie).permit(:title, :description, :has_subtitles,
    :placement, :mpaa_rating, :release_date, :ticket_price, :runtime, :poster_image)

  4. Select the code and cut it (Cmd–X).

  5. Paste it as follows in the private movie_params method:

       private
          def movie_params
          movie_params = params.require(:movie).permit(...)
       end
    end
    
  6. Remove the movie_params = part so the complete line looks like this:

       private
          def movie_params
          params.require(:movie).permit(...)
       end
    end
    
  7. Find the create method around line 26 and delete the identical line of code for movie_params. From now on, when movie_params is invoked, it will be fetched from the private method at the bottom of the file.

  8. Another reason our code is not terribly DRY is that we’re calling @movie = Movie.find(params[:id]) several times. That’s unnecessary repetition, so let’s create another private method. Above the movie_params method create another private method:

    private
       def set_movie
    
       end
    
       def movie_params
    
  9. Find the edit method around line 35:

    def edit
       @movie = Movie.find(params[:id])
    end
    
  10. Cut (Cmd–X) the @movie = Movie.find(params[:id]) line so it looks like this:

    def edit
    end
    
  11. Paste the code into the private set_movie method as follows:

    private
       def set_movie
          @movie = Movie.find(params[:id])
       end
    
  12. Delete the @movie = Movie.find(params[:id]) line in the following methods:

    • The update method (around line 39)
    • The show method (around line 13)
  13. At the very top of the file add the following just beneath the class definition:

    class MoviesController < ApplicationController
       before_action :set_movie, only: [:show, :edit, :update]
    
       def about
       end
    

    This code we just wrote is going to be called at the beginning of each specified method. We don’t need to explicitly set the movie instance variable in every method, just three of them: show, edit, and update. We can use the only parameter and an array of those method names to specify exactly which ones.

  14. Save the file.

  15. Switch to Terminal and type the following to launch the server:

rails server

  1. Switch to the browser and reload localhost:3000/movies/4/edit to make sure everything is still working. Click around the Flix site. Everything should be looking good, and our code is much DRYer too!

  2. Back in Terminal hit Ctrl–C to shut down the server.

How to Learn Coding

Master coding with hands-on training. Learning how to code in JavaScript, Python, and other popular languages can pave the way to a job in tech, such as web development, data science & analytics, or software engineering.

Yelp Facebook LinkedIn YouTube Twitter Instagram