Difference between form_for and form_tag helper tags in rails

4 Comments

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

Quick RubyOnRails Helper Example

2 Comments

Note: This example comes from Michael Hartl’s excellent RubyOnRails book. Go there for the full example.

Last post we saw how you could dynamically add content to your Rails page, and then extract common HTML using layouts.

app/views/layouts/application.html.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>Ruby on Rails Tutorial Sample App | <%= @title %></title>
</head>
<body>
   <%= yield %>
</body>
</html>

But what if your controller doesn’t define a title attribute? Or it is null?
To define a base title class that will always have a default value we can use Rails helpers.

app/helpers/application_helper.rb

module ApplicationHelper

   # Return a title on a per-page basis.
   def title
      base_title = "Ruby on Rails Tutorial Sample App"
      if @title.nil?
         base_title
      else
         "#{base_title} | #{@title}"
      end
   end
end

This helper (which is tied to the application.html.erb file) can be used to set a default title for any page, and add a specific title if one is defined in a view.

Now instead of:

<title>Ruby on Rails Tutorial Sample App | <%= @title %></title>

We can have:

<title><%= title %></title>

Note: no @ sign in front of title here.

Helpers are Rails way of helping you separate presentation from logic. You can test and put logic in controllers and small helpers, and keep your UI clean by not cluttering it up with extra code.

To get the full (and much better) story on helpers be sure to check out Michael Hartl’s excellent book from where this example came.

%d bloggers like this: