Using form_with vs form_for vs form_tag

Facebook
Twitter
LinkedIn

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 %>

Want more posts like this?

What you should do now:

Facebook
Twitter
LinkedIn

Easy Application Deployment to AWS

Focus on development, not on managing infrastructure

Deploying, running and managing your Ruby on Rails app is taking away precious resources? Engine Yard takes the operational overhead out of the equation, so you can keep innovating.

  • Fully-managed Ruby DevOps
  • Easy to use, Git Push deployment
  • Auto scaling, boost performance
  • Private, fully-configured Kubernetes cluster
  • Linear pricing that scales, no surprises
  • Decades of Ruby and AWS experience

14 day trial. No credit card required.

Sign Up for Engine Yard

14 day trial. No credit card required.

Book a Demo