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