form_for(object_name, *args, &proc) public

Creates a form and a scope around a specific model object, which is then used as a base for questioning about values for the fields. Examples:

  <% form_for :person, @person, :url => { :action => "update" } do |f| %>
    First name: <%= f.text_field :first_name %>
    Last name : <%= f.text_field :last_name %>
    Biography : <%= f.text_area :biography %>
    Admin?    : <%= f.check_box :admin %>
  <% end %>

Worth noting is that the form_for tag is called in a ERb evaluation block, not a ERb output block. So that’s <% %>, not <%= %>. Also worth noting is that the form_for yields a form_builder object, in this example as f, which emulates the API for the stand-alone FormHelper methods, but without the object name. So instead of text_field :person, :name, you get away with f.text_field :name.

That in itself is a modest increase in comfort. The big news is that form_for allows us to more easily escape the instance variable convention, so while the stand-alone approach would require text_field :person, :name, :object => person to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with :person, person and all subsequent field calls save :person and :object => person.

Also note that form_for doesn’t create an exclusive scope. It’s still possible to use both the stand-alone FormHelper methods and methods from FormTagHelper. Example:

  <% form_for :person, @person, :url => { :action => "update" } do |f| %>
    First name: <%= f.text_field :first_name %>
    Last name : <%= f.text_field :last_name %>
    Biography : <%= text_area :person, :biography %>
    Admin?    : <%= check_box_tag "person[admin]", @person.company.admin? %>
  <% end %>

Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base. Like collection_select and datetime_select.

Html attributes for the form tag can be given as :html => {…}. Example:

  <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %>
    ...
  <% end %>

You can also build forms using a customized FormBuilder class. Subclass <a href="/rails/ActionView/Helpers/FormBuilder">FormBuilder</a> and override or define some more helpers, then use your custom builder like so:

  <% form_for :person, @person, :url => { :action => "update" }, :builder => LabellingFormBuilder do |f| %>
    <%= f.text_field :first_name %>
    <%= f.text_field :last_name %>
    <%= text_area :person, :biography %>
    <%= check_box_tag "person[admin]", @person.company.admin? %>
  <% end %>

In many cases you will want to wrap the above in another helper, such as:

  def labelled_form_for(name, object, options, &proc)
    form_for(name, object, options.merge(:builder => LabellingFormBuiler), &proc)
  end
Show source
Register or log in to add new notes.
July 22, 2008
15 thanks

Nested resources in form_for

If you like doing things RESTfully and have a model relationship like:

 Post_ has many Comments_

Then you can construct a form_for within your view to mirror this relationship when creating comments:

 form_for [@post, @comment] do |f|
   ...
 end

You also need to make sure your routes reflect this relationship:

 map.resources :post, :has_many => [:comments]
August 5, 2008
11 thanks

Multipart form

Don’t forget to add :multipart => true if you have file upload in your form.

 <% form_for "user", :html => { :multipart => true } do |f| %>
September 28, 2008 - (v2.0.0 - v2.1.0)
3 thanks

has_one Nesting in Rails 2.0

Routers:

  map.resources :user, :has_one => [:avatar]

Views:

  form_for [@user, @avatar], :url => user_avatar_url(@user) do |f|
  ...
  end
September 25, 2008 - (v2.1.0)
3 thanks

Compare old and new form for

Old form for

  <% form_for :user, :url => users_path do %>
    <%= render :partial => 'form' %>
    <%= submit_tag 'Create' %>
  <% end %>

New form for

  <% form_for(@user) do |f| %>
    <%= render :partial => f %>
    <%= submit_tag 'Create' %>
  <% end %>
January 27, 2009 - (>= v2.2.1)
2 thanks

Getting the object in a partial

If you need to get the object for the form inside a partial, and can’t use the instance variable, use the #object method… This is particularly useful when you’re dealing with single-table inheritance subclasses (e.g. MyOtherClass inherits from MyClass) or when you are using the same partial across different controllers.

new.html.erb

  <% form_for(@my_object) do %>
    <%= render :partial => 'form' %>
    <%= submit_tag 'Create' %>
  <% end %>

_form.html.erb

  <% if f.object.class.is_a? MyClass %>
   <%# do something... %>
  <% elsif f.object.is_a? MyOtherClass %>
    <%# do something else... %>
  <% end %>
November 2, 2008
2 thanks

params hash gets the model id automatically

The params hash gets automatically populated with the id of every model that gets passed to form_for. If we were creating a song inside an existing album:

  URL:/albums/209/songs/new
  form_for [@album, @song] do |f|
    ...
    f.submit "Add"
  end

The params hash would be:

  params = {"commit"=>"Add",
            "authenticity_token"=>"...",
            "album_id"=>"209",
            "song"=>{"song_attributes"=>{...}}
            }

So, in the songs_controller you could use this album_id in a before_filter:

  before_filter :find_album
  protected
  def find_album
    @album = Album.find(params[:album_id])
  end

If you only did this:

  form_for @song do |f|

You would get this params hash:

  params = {"commit"=>"Add",
            "authenticity_token"=>"...",
            "song"=>{"song_attributes"=>{...}}
            }
October 8, 2008
2 thanks

Seriously! Do not forget the brackets

thank you source jamesandre.ws

the form_for([:admin, @user]) must have the [] brackets to avoid errors like "Only get requests are allowed"

 <% form_for([:admin, @user]) do |f| %>
 <%= render :partial => 'form' %>
 <%= submit_tag "Create" %>
 <% end %>
November 4, 2009
1 thank

Using hidden tags

To use an <input type="hidden" /> tag, use the following syntax:

  <% form_for(@post) do |f| %>
    <%= f.hidden_field :user_id, { :value => user.id } %>
  <% end %>