Giter VIP home page Giter VIP logo

rails-form_for-on-edit-readme's Introduction

The form_for Helper

If you know how to utilize the form_tag method for creating forms in Rails you may wonder why you need to learn a new form building process. Let's imagine that you've been tasked with creating the world's first pet hamster social network, and one of the requirements is that the hamster profile page needs to have about 100 different form fields that can be edited. If you are using the form_tag method, your application will be technically resubmitting all 100 fields each time you edit the data. Your form view templates will also have 100 calls to the @hamster instance variable and each of the hamster attributes. Thankfully form_for is here and will help clean up the form view template and provide some additional benefits that we'll explore in this lesson.

Recap of form_tag

To review, the form_tag helper method allows us to automatically generate HTML form code and integrate data to both auto fill the values as well as have the form submit data that the controller can use to either create or update a record in the database. It allows for you to pass in: the route to which the parameters for the form will be sent, the HTTP method that the form will utilize, and the attributes for each field.

Issues with using form_tag

Before we get into the benefits and features of the form_for method, let's first discuss some of the key drawbacks to utilizing form_tag:

  • Our form must be manually passed to the route where the form parameters will be submitted

  • The form has no knowledge of the form's goal; it doesn't know if the form is meant to create or update a record

  • You're forced to have duplicate code throughout the form; it's hard to adhere to DRY principles when utilizing the form_tag

Difference between form_for and form_tag

The differences between form_for and form_tag are subtle, but important. Below is a basic breakdown of the differences. We'll start with talking about them at a high level perspective and then get into each one of the aspects on a practical/implementation basis:

  • The form_for method accepts the instance of the model as an argument. Using this argument, form_for is able to make a bunch of assumptions for you.

  • form_for yields an object of class FormBuilder

  • form_for automatically knows the standard route (it follows RESTful conventions) for the form data as opposed to having to manually declare it

  • form_for gives the option to dynamically change the submit button text (this comes in very handy when you're using a form partial and the new and edit pages will share the same form, but more on that in a later lesson)

A good rule of thumb for when to use one approach over the other is below:

  • Use form_for when your form is directly connected to a model. Extending our example from the introduction, this would be our Hamster's profile edit form that connects to the profile database table. This is the most common case when form_for is used

  • Use form_tag when you simply need an HTML form generated. Examples of this would be: a search form field or a contact form

Implementation of form_for

Let's take the edit form that utilized the form_tag that we built before for posts and refactor it to use form_for. As a refresher, here is the form_tag version:

<% # app/views/posts/edit.html.erb %>
<h3>Post Form</h3>

<%= form_tag post_path(@post), method: "put" do %>
  <label>Post title:</label><br>
  <%= text_field_tag :title, @post.title %><br>

  <label>Post description</label><br>
  <%= text_area_tag :description, @post.description %><br>

  <%= submit_tag "Submit Post" %>
<% end %>

Let's take this refactor one element at a time. Since we already have access to the @post instance variable we know that we can pass that to the form_for method. We also can remove the path argument and the method call since form_for will automatically set these for us. How does form_for know that we want to use PUT for the form method? It's smart enough to know that because it's dealing with a pre-existing record you want to utilize PUT over POST.

<%= form_for(@post) do |f| %>

The |f| is an iterator variable that we can use on the new form object that will allow us to dynamically assign form field elements to each of the @post's data attributes, along with auto filling the values for each field. We get this ActionView functionality because we're using the form_for method, which gives us access to the FormBuilder module in Rails. Inside of the form, we can now refactor the fields:

<label>Post title:</label><br>
<%= f.text_field :title %><br>

<label>Post description</label><br>
<%= f.text_area :description %><br>

Isn't that much cleaner? Notice how we no longer have to pass in the values manually? By passing in the attribute as a symbol (e.g. :title) that will automatically tell the form field what model attribute to be associated with. It also is what auto-fills the values for us. Next, let's refactor the submit button. Instead of <%= submit_tag "Submit Post" %>, we can change it to:

<%= f.submit %>

Our new form will look something like this:

<h3>Post Form</h3>

<%= form_for(@post) do |f| %>
  <label>Post title:</label><br>
  <%= f.text_field :title %><br>

  <label>Post description</label><br>
  <%= f.text_area :description %><br>

  <%= f.submit %>
<% end %>

Our refactor work isn't quite done. If you had previously created a PUT route like we did in the form_tag lesson, we'll need to change that to a PATCH method since that is the HTTP verb that form_for utilizes. We can make that change in the config/routes.rb file:

# config/routes.rb
resources :posts, only: [:index, :show, :new, :create, :edit, :update]
patch 'posts/:id', to: 'posts#update'

What's the difference between PUT and PATCH? It's pretty subtle. On a high level, PUT has the ability to update the entire object, whereas PATCH simply updates the elements that were changed. Many developers choose to utilize PATCH as much as possible because it requires less overhead; however, it is pretty rare when you will need to distinguish between the two verbs, and they are used interchangeably quite often.

You can also add update as an additional argument in the resources method array, and this will all happen automatically.

Now if you start the Rails server and go to an edit page, you'll see that the data is loaded into the form and everything appears to be working properly. However, if you change the value of one of the form fields and click Update Post, you will see that the record updates incorrectly. So what's happening? When you run into behavior like this, it's good practice to look at the console logs to see if they tell us anything. Below is an example of what you might see after submitting the form:

Unpermitted Parameters

Because form_for is bound directly with the Post model, we need to pass the model name into the Active Record update method in the controller. Let's change @post.update(title: params[:title], description: params[:description]) to:

@post.update(params.require(:post).permit(:title, :description))

So, why do we need to require the post model? If you look at the old form, the params would look something like this:

{
  "title": "My Title",
  "description": "My description"
}

With the new structure introduced by form_for, the params now look like this:

{
  "post": {
    "title": "My Title",
    "description": "My description"
  }
}

Notice how the title and description attributes are now nested within the post hash? That's why we needed to add the require method. But Rails wants us to be conscious of which attributes we allow to be updated in our database, so we must also permit the title and description in the nested hash. Using strong parameters like this will allow ActiveRecord to use mass assignment without trouble.

If you go back to the edit page and submit the form, the record will be updated in the database successfully.

Summary

Nice work! You now know how to integrate multiple form helpers into a Rails application, and you should have a good idea on when to properly use form_for vs. form_tag.

rails-form_for-on-edit-readme's People

Contributors

annjohn avatar bhabig avatar coltonstaab1 avatar danielseehausen avatar dependabot[bot] avatar drakeltheryuujin avatar franknowinski avatar hyeokjungkim avatar ihollander avatar jordanhudgens avatar joshrowley avatar lharary avatar lizbur10 avatar maxwellbenton avatar nathaniel-miller avatar onyoo avatar sgharms avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rails-form_for-on-edit-readme's Issues

Terrible ordering of labs.

The bad ordering of the labs has really hindered my learning. You've had us building things with all of the routes and then put us through tutorials of each of the singular routes on there own.

Had us using form_for before the readme on form_for. Just all around its been ordered terrible. Please review the ordering of these labs for future students. It would have saved me a lot of wasted time, stress and effort.

Reorder lesson

This README would've been helpful if it were before the previous lab "Edit/Update Action".
In that previous lab, it suddenly used form_for without explaining it, and now it is being explained in this later lesson.

readme says add patch but not other paths

readme told to put patch 'posts/:id', to: 'posts#update'

but lab doesn't default with index show new create and edit paths

had to add resources :posts, only: [:index, :show, :new, :create, :edit, :update]

minor, but still tangible

form_tag syntax

under Implementation of form_for it shows a method in the form_tag syntax, but in the previous lab for the rails form_tag doesn't show or walk through a method

Put/Patch/Resources Inconsistency

I'd like to suggest some scrubbing of the this lesson to fix consistency issues. Our cohort has been taught to use PATCH over PUT both in learn curriculum and lectures. Either way, the curriculum has some discrepancies.

  • README line 60 says: "It [form_for] is smart enough to know that since it's dealing with a pre-existing record you want to utilize PUT over POST."
    -README line 98 says: "Our refactor work isn't quite done. If you had previously created a PUT route like we did in the form_tag lesson, we'll need to change that to a PATCH method since that is the HTTP verb that form_for utilizes." Screen shot below is from the Edit/Update Action codalong lesson that recommends using PATCH and explaining the difference--if referring to the Rails form_tag lesson in the Active View section, it does not mention either PATCH or PUT
    -README line 98-106: Says that we need to make an alteration to the routes.rb file to add line 106 to "patch 'posts/:id". First, the codealong route.rb file is currently blank when forked and cloned. Second, line 102 already has :update as one of the actions, so line 106 is confusing since 'resources' automatically implements a PATCH HTTP request with an :update. I think this could cause unnecessary confusion.
    -Also, the error logging below the above lines seems to be out of date

Separate from the inconsistencies I highlighted, I'd like to suggest altering lessons on the subject of forms to use any case other than a "blog." The instance variable in blog cases is "@post" which has the potential to confuse students when also referring to the POST HTTP request verb.

Edit:Update Action Codealong Patch

Forbidden attributes error with params.require

Using @post.update(params.require(:post)) as instructed in the Readme results in a forbidden attributes error. To get the tests to pass, it's necessary to use @post.update(title: params[:post][:title], description: params[:post][:description]) instead.

frequent issues with forking and cloning labs

I used to be in the in-person bootcamp, and then got into the online one. But I was gone from the course for a long time. Now that I've started back up again, I have some problems with forking and cloning labs that seem to stem from that transfer.

This leads to frequent and time-consuming conversations with tech coaches outside of the actual coding for the labs, but just to get the lab open and the tests working. The coaches are skillful and always eventually figure it out, but I'm opening an issue as it seems to be rooted in an ongoing problem. I also can't stay for the Ask A Question session which is currently ongoing.

When I click the github button to fork down labs, it doesn't get them from learn-co account which issues the v-000 suffix in the url, like in this one:
https://github.com/learn-co-students/rails-form_for-on-edit-readme-v-000

Instead, mine look like this:
https://github.com/ode-to-the-code/strong-params-basics-web-051517

And when I use that button, the labs seem to fork from a different source altogether than the learn account:
ode-to-the-code/strong-params-basics-web-051517
forked from procchio6/strong-params-basics-web-051517

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.