Jan 27 2010
Using form_tag in Ruby on Rails
I had some trouble finding a less than simplistic example of using the form_tag in Rails yesterday and, after griping on twitter about it was called out and told to do it myself. Good advice. Here we go.
In Rails you’ve got two ways to create a form: form_for and form_tag. You see examples for form_for everywhere, because that’s what you use to directly interact with the models you created in your database. But a lot of times you need to create a form that has no interaction with your database and that isn’t mapped to any data model. Enter form_tag.
There are two syntatic differences between forms created with form_for and those with form_tag. First, you typically declare form_for like this:
<% form_for(@person) do |f| %>
And from then on you add fields using the f variable you just defined, like f.text_field or f.select. The other difference is that the way you declare the fields themselves changes. text_field becomes text_field_tag, select becomes select_tag and so on. The reason is that text_field is meant, just like form_for, to interact with a defined object model. All those ones ending in _tag are for unbound forms.
<% form_tag(create_ticket_path, :method=>'post', :multipart => true) do %>
In the example, you see a couple of things. First, when defining a form_tag you can’t just pass it an object and let rails figure out what needs to happen. You need to tell it, first, what URL to point at and, second, what HTTP call to make (typically post or put). Those are the first two parameters. In my case, I have a path defined in my routes.rb for create_ticket, so I can call create_ticket_path to get it. And I’m creating a support ticket, so I’m going to use the ‘post’ method.
The third parameter is where you pass your options, which are roughly the same as the options you can pass form_for. You’ll see in mine I passed it :multipart => true. I do that to define a multipart form so that I can let people upload a file on submission.
The other thing to note is when defining the input fields. When using form_for, you can just pass, say, text_field the symbol for the field you want it bound to. So, if you were creating a field for the subject of a support ticket request, you’d do:
<%= f.text_field :subject %>
Rails figures out the rest. Without the model, we need to do it ourselves and define the field’s id. (If you wanted to have a default value, you’d put it in the second parameter, but for this example it doesn’t really make sense).
<%= text_field_tag "subject" %>
Pretty simple, I know. But sometimes you just need to see how the syntax works, and it felt like every tutorial assumed every form would either use Rails’ models and form_for, or your form_tag usage would be hilariously simple. The full example of the form is below. Just like when you use form_for, if you’re catching this with a rails controller, everything will be available through the params[] array. So, to catch that text_field_tag “subject” all you have to do in your controller is grab for params[:subject] .
File uploads are their own story, but to get you started, it’ll be in params just like everything else. Just be sure to use :multipart => true or your form will quietly ignore that an attachment was chosen.
Easy, right?
<% form_tag(create_ticket_path, :method=>'post', :multipart => true) do %>
<p>
Subject:<br />
<%= text_field_tag "subject" %>
</p>
<p>
Priority: <br />
<%= select_tag("priority", options_for_select([['Critical', '1'],
['Important', '2'],['Standard','3']], '3')) %>
</p>
<p>
Describe your problem:<br />
<%= text_area_tag "description", "", :size=>"50x20" %>
</p>
<p>
Add an attachment:<br />
<%= file_field_tag "attachment" %>
</p>
<p>
<%= submit_tag 'Submit' %>
</p>
<% end %>
Great article :)
Simple and effective article…Was looking for similar info and basic example of form_tag so thanks!
How can I group params in form_tag?
For example, what if I want the params[:subject] and params[:description] to be grouped into
params[:ticket][:subject], and
params[:ticket][:description] ?
such that the form_tag variables are not ‘mixed’ with other params (e.g. params[:action], params[:controller]. …, etc.)
thx, and great article!
This really helped me in in designing a submission form for my language learning site iLearnWords (http://www.ilearnwords.com) — thank you!
BSise
Thanks very much! Great, focused tutorial.
Good work – helped this newbie! Have you considered doing an article on fields_for as well?
This article was very helpful. Thank you :)
Hi,
Nice article, just what I needed, sometimes the Rails API docs really are sparse.
A note for new users like me, the code to do something with the data you get form the user goes in the same controller method as the one that called the page in the first place, typically this is your index method.
Richard.
IT Contractor Mortgages
nice work! It will help the newbie(me too) for rails…
very good and clear information
Thanks a ton for this.
I’m having some trouble on getting that to work. I want to pass a work_hours param. My route is :
post ‘start/:work_hours’ => :start, :as => ‘start’
My code is :
:post do %>
But i get a “No route matches {:controller=>”labor”, :action=>”start”}” when rendering the form. Any idea on what i’m doing wrong ? :/
Spyros,
Is the comment system cutting off part of your code? What you posted looks a little incomplete. I don’t think WordPress does a great job handling code in comments.
I suggest posting your question on http://stackoverflow.com and, if you’d like, leaving the link to the question here. I’d be happy to answer it (and if I can’t, someone else there probably can).
Eric
fine explanation
thanks a lot.. great work
Awesome article, just what I needed when I was about ready to throw my laptop out the window because form_tag was breaking my code. Thanks!
[...] been there. I hope my post helped. Truly and [...]
Very helpful, thanks! The Rails documentation doesn’t really lend a hand here.