Using form_with vs form_for vs form_tag

  

source code form.jpg

Prior to Rails 5.1, Rails provided 2 form helpers, form_for and form_tag. You use form_for with a model and form_tag for custom URLs. Both generate HTML for a form. There are only a few minor differences so Rails 5.1 combined the two. You should now be using form_with.

form_with can do what the two old methods can do. When you pass a model, it acts the same as form_for. For example, if you have a Message model,

<%= form_with model: Message.new do |form| %>
  <%= form.text_field :subject %>
<% end %>

would generate

<form action="/messages" method="post" data-remote="true">
  <input type="text" name="subject">
</form>

If you have an existing model, the form will have the values filled in and the action would contain the ID i.e. it would go to the show action on the controller.

# controller
# @message = Message.first 

<%= form_with model: @message do |form| %>
  <%= form.text_field :subject %>
<% end %>

The form is similar to the one above. Because @message is an existing object, the generated form is different.

<form action="/messages/1" method="post" data-remote="true">
  <input type="hidden" name="_method" value="patch">
  <input type="text" name="message[subject]" value="<the subject of the message>">
</form>

If you don't pass a model, form_with behaves like form_tag.

<%= form_with url: messages_path do |form| %>
  <%= form.text_field :subject %>
<% end %>

would generate

<form action="/messages" method="post" data-remote="true">
  <input type="text" name="subject">
</form>

Options

form_with submits are remote by default (data-remote="true"). You can change this by using local: true. This is the opposite from the old methods where the default is local and you have to specify remote: true to make it remote.

<%= form_with(model: Message.new, local:true) do |form| %>
  <%= form.text_field :subject %>
<% end %>

You can also specify options available with form_for and for_tag like id, class, html, and data.

<%= form_with(model: Message.new, data: { behavior: "autosave" }, html: { name: "go" }) do |form|
  <%= form.text_field :subject %>
<% end %>

Free Ebook:
Should I Hire DevOps or Outsource to a Provider?

You have to invest in your infrastructure: Do you hire DevOps for this critical function, assign it to your already overworked engineers, or outsource to a provider that offers full-stack capabilities?

Should I Hire DevOps?

Christopher Rigor

 
DevOps Support Manager, Asia-Pacific at Engine Yard. Organizer of @RubyConfPH. Speaker. Interested in automation, Kubernetes, Docker, Deis, ops, Ruby.
Find me on:

Comments

Subscribe Here!