Types of forms

Pål Bergström wrote:

I'm I right that there are two kinds of forms in an edit page? One is:

<%= start_form_tag :action => 'update', :id => @content %>   <%= render :partial => 'form' %>

This will simply output the columns in the database.

No. There is no automatic form system in Rails. With the code above, you still need to create a partial template called _form.rhtml, and in that you need to write view code that specifies which fields you want to appear and how you want them laid out.

The other is:

<% form_for :content, :url => { :action => "update" } do |f| %>

Here you are more free to select what to display from the db than the first.

No. As described above, with either method you have equal freedom in terms of layouts and which fields you include, because with both methods you have to write the view code manually.

But can you use the first and tell RoR not to render/output a particular field?

Yes, as described above.

And can the second be written in another way? Does it need :url? Why not just the :action?

Yes, it does need :url. The start_form_tag method call actually looks like this:

start_form_tag({:action => 'update', :id => @content})

it's just that Ruby puts in those {curly braces} for you automatically because it sees that you're giving it a hash. So that hash in there is actually just the first parameter to the start_form_tag. There is an optional second parameter to the start_form_tag method that lets you specify HTML options, such as :multipart => true. If you wanted to specify some HTML options, you'd have to write out the hashes explicitly:

start_form_tag({:action => 'update', :id => @content}, {:multipart => true})

This won't work:

start_form_tag(:action => 'update', :id => @content, :multipart => true)

because you're mixing up HTML options with a URL specification.

With this in mind, we can look at the form_for method call:

form_for(:content, :url => {:action => 'update'})

As with start_form_tag, you can specify HTML options too:

form_for(:content, :url => {:action => 'update}, :html => {:multipart => true})

The difference is just a difference in style. Recently in Rails, methods have tended to look more like form_for than start_form_tag, for two reasons: 1. It makes it very clear that there are two separate bits and you need to specify them separately; 2. It makes it very clear what each bit is relating to (this here is the URL stuff, and this here is the HTML stuff).

The upshot of all of this is that, yes, you do need to use :url when you're calling form_for.

The real difference between form_for (beyond the style difference) is that form_for reduces repetition if you're writing a lot of fields for the same object. And it lets you easily create a form for the attributes of (say) a local variable 'person', rather than the instance variable '@person' that start_form_tag and its helpers expect.

To create a form for the 'person' variable using start_form_tag, you'd have something like:

<%= start_form_tag(:action => 'update', :id => person) %> <%= text_field(:person, :name, :object => person) %> <%= text_field(:person, :job, :object => person) %> <%= end_form_tag %>

Very repetitive. Using form_for, it would look like this:

<% form_for(:person, person, :url => {:action => 'update', :id => person} do |f| -%> <%= f.text_field(:name) %> <%= f.text_field(:job) %> <% end -%>

Much nicer.

Chris