Rafe Draper
Rafe Draper's Blog


Rafe Draper's Blog

Rendering Forms with Rails 6 (GREEN)

Rendering Forms with Rails 6 (GREEN)

Rafe Draper's photo
Rafe Draper
·Jul 16, 2020·

5 min read

Today I learned a new way to render forms from my views with a Rails method, especially for Forms: form_with. My previews post was about how display a form with previously written data, edit the form and then submit it to update the element in question. First I will begin with the test I wrote before I began creating anything else. This is my first TDD (Test Driven Development) unit created so this was a great improvement in my learning curve.

Let's begin with the test unit:

describe '#edit' do
    context 'authenticated' do
      let(:user) { FactoryBot.create(:user, :admin) }
      let(:item) { FactoryBot.create(:meetings_item) }

      it 'edits an item' do
        item_params = FactoryBot.attributes_for(:meetings_item, reason: 'test reason')
        patch(:update, params: { meetings_list_id: item.meetings_list.id,
                                 id: item.id,
                                 meetings_item: item_params })
        expect(item.reload.reason).to eq('test reason')
        expect(flash[:notice]).to match(/Item erfolgreich aktualisiert/)

As previously explained I began with RED and refactored it until GREEN, by creating the Controller(MeetingsItem) methods #edit, #update and a view in order to create an edit form which will retrieve the information from the item to be edited.

So I created first an edit view:

# app/views/meetings_items/edit.html.slim

  | Bearbeiten Eintrag
    = render 'edit_form'
    = link_to 'Cancel', @meetings_list

Here I created an additional form partial, to me It was more clear to have another form with different method than the original which was made to create a new item. So I created the partial _edit_form.html.slim inside of app/views/meetings_items/ that looks like this:

- provide(:title, "#{@meetings_list.title}")
= form_with(model: [ @meetings_list, @meetings_item ], local: true, method: :put) do |form|
  = render 'eintrag_errors'
    = form.label :date, "Datum:"
    = form.text_field :date, data: {controller: "flatpickr", 
                                 flatpickr_alt_format: t("date.formats.long"),
                                 flatpickr_alt_input: true,
    = form.label :amount, "Betrag:"
    = form.text_field :amount, class: "currency-input-mask"
    = form.label :reason, "Grund:"
    = form.text_field :reason
    = form.submit value: "Neuer Eintrag"

let me begin with the second line of the code which was something new to me, previously I had this line:

= form_for [@meetings_list, @meetings_list.meetings_items.build] do |f| ...

which was presenting a form and a new element, the parameters were missing in order to catch the data from the item and present it in order to edit it. Which lead me to search more about the form_for and form_with methods. This post from helped me understanding better that method and why I decided to unify my app and forms to form_with instead of form_for or form_tag. I could dedicate this whole entry just to that method, so this is why I will just leave the link which includes more resourceful links in order for anyone else interested in learning deeper into it.

So, what did I change? the model: [] here there are two parameters which form_with allows you to specify dependencies with other Controllers, in this case the first @meetings_list with @meetings_item here I believe there are many ways to write but this was the one who worked for me, more suggestions are more than welcome! Then the parameter local: true, as found in the documentation page here , it states:

> :local - By default form submits are remote and unobtrusive XHRs. Disable remote submits with local: true

If I didn't specify this parameter, the validation errors from my form were not displayed, why? What does this means?

"unobtrusive XHRs"

And last I added the method: :put which made sense to me since I don't want to create a new item out of this form, I want to update an existent one. So this worked and updated my item. Here a couple of pics on how it worked:

Screenshot_2020-07-16 Spende App List tittle Edit.png

Screenshot_2020-07-16 Spende App List tittle Edit(1).png

Screenshot_2020-07-16 Spende App List tittle Edit(2).png

Share this