form_for helper (use for posting new resources)

http://localhost:3000/projects

form_for is the helper method rails provides for you when you create a new resource using scaffolding:

> rails generate scaffold Project name:string

<%= form_for(@project) do |f| %>
 
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
 
  <div class="actions">
    <%= f.submit %>
  </div>

<% end %>

And it produces HTML that looks like this:

<form action="/projects" id="new_project" method="post">
 
  <div class="field">
    <label for="project_name">Name</label><br />
    <input id="project_name" name="project[name]" type="text" />
  </div>

  <div class="actions">
    <input name="commit" type="submit" value="Create Project" />
  </div>

</form>

It knows where to route this request because scaffolding adds ‘projects’ to the routes table:

routes.rb
Foo::Application.routes.draw do
  resources :projects

But before it will render we need to setup the @project variable in our controller (which scaffolding thankfully does for us):

class ProjectsController < ApplicationController
  def new
    @project = Project.new
  end
end

That in a nutshell is mechanics behind form_for.

form_tag (use for generic posts i.e. search)

form_tag is different. With form_tag we aren’t updating a resource. We just want to create a form and send something to the backend via a post (i.e. we want to do a search).

<h1>Listing projects</h1>

<%= form_tag projects_path do %>
  <p>
    <%= text_field_tag :search %>
    <%= submit_tag "Search" %>
  </p>
<% end %>

This renders:

<h1>Listing projects</h1>
 
<form action="/projects" method="post">
  <p>
    <input id="search" name="search" type="text" />
    <input name="commit" type="submit" value="Search" />
  </p>
</form>

Now by default if we just left this like this and tested out our new search it wouldn’t work.

Instead of doing a search for us (which we haven’t defined yet) it would try to create a new project because of the ‘post’ method in the form action.

So what we need to do is turn this into a ‘get’.

<%= form_tag projects_path, :method => 'get' do %>

And then implement some search:

class ProjectsController < ApplicationController

  def index
    if params[:search]
      @projects = Project.find(:all, :conditions => ['name LIKE ?', "%#{params[:search]}%"])
    else
      @projects = Project.all
    end
  end

Note: the URL for our search is:

http://localhost:3000/projects?search=foo&commit=Search

Thanks to Ryan Bates for his rails cast (of which this post is based)

http://railscasts.com/episodes/37-simple-search-form

And Michael Hartl’s excellent:

http://ruby.railstutorial.org/chapters/sign-up#sec:using_form_for