Ruby-on-Rails
  Home arrow Ruby-on-Rails arrow Web Forms and Ruby on Rails
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Mobile Linux 
App Generation ROI 
IBM® developerWorks 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
RUBY-ON-RAILS

Web Forms and Ruby on Rails
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 8
    2007-04-19

    Table of Contents:
  • Web Forms and Ruby on Rails
  • 15.17 Creating an Ajax Form
  • 15.18 Exposing Web Services on Your Web Site
  • 15.19 Sending Mail with Rails

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    Web Forms and Ruby on Rails


    (Page 1 of 4 )

    In this fifth article of a six-part series covering web development and Ruby on Rails, you'll learn how to create an AJAX form and more. This article is excerpted from chapter 15 of the Ruby Cookbook, written by Lucas Carlson and Leonard Richardson (O'Reilly, 2006; ISBN: 0596523696). Copyright © 2006 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

    15.16 Generating Forms for Manipulating Model Objects

    Problem

    You want to define actions that let a user create or edit objects stored in the database.

    Solution

    Let's create a simple model, and then build forms for it. Here's some MySQL code to create a table of key-value pairs: 

      use mywebapp_development;
      DROP TABLE IF EXISTS items;
      CREATE TABLE `items` (
        `id` int(11) NOT NULL auto_increment,
        `name` varchar(255) NOT NULL default '',
        `value` varchar(40) NOT NULL default '[empty]',
        PRIMARY KEY (`id`)
     
    );

    Now, from the command line, create the model class, along with a controller and views:

      $ ./script/generate model Item
            exists  app/models/
            exists  test/unit/
            exists  test/fixtures/
            create  app/models/item.rb
            create  test/unit/item_test.rb
            create  test/fixtures/items.yml
            create  db/migrate
            create  db/migrate/ 001_create_items.rb

      $ ./script/generate controller items new create edit
            exists  app/controllers/
            exists  app/helpers/
            create  app/views/items
            exists  test/functional/
            create  app/controllers/ items_controller.rb
            create  test/functional/ items_controller_test.rb
            create  app/helpers/items_helper.rb
            create  app/views/items/new.rhtml
            create  app/views/items/edit.rhtml

    The first step is to customize a view. Let's start with app/views/items/new.rhtml. Edit it to look like this:

      <!-- app/views/items/new.rhtml -->

      <%= form_tag :action => "create" %>
       Name: <%= text_field "item", "name"
    %><br />
       Value: <%= text_field "item", "value"
    %><br />
       <%= submit_tag %>
      <%= end_form_tag %>

    All these method calls generate HTML: form_tag opens a <FORM> tag, submit_tag generates a submit button, and so on. You can type out the same HTML by hand and Rails won't care, but it's easier to make method calls, and it makes your templates neater.

    The text_field call is a little more involved. It creates an <INPUT> tag that shows up in the HTML form as a text entry field. But it also binds the value of that field to one of the members of the @item instance variable. This code creates a text entry field that's bound to the name member of @item:

      <%= text_field "item", "name" %>

    But what's the @item instance variable? Well, it's not defined yet, because we're still using the generated controller. If you try to access the page /items/new page right now, you may get an error complaining about an unexpected nil value. The nil value is the @item variable, which gets used (in text_field calls) without ever being defined.

    Let's customize the ItemsController class so that the new action sets the @item instance variable properly. We'll also implement the create action so that something actually happens when the user hits the submit button on our generated form.

      class ItemsController < ApplicationController
        def new
          @item = Item.new
        end

        def create
          @item = Item.create(params[:item])
          redirect_to :action => 'edit', :id => @item.id
       
    end
      end

    Now if you access the /items/new page, you'll see what you'd expect: a form with two text entry fields. The "Name" field will be blank, and the "Value" field will contain the default database value of "[empty]".

    Fill out the form and submit, and a new row will be created in the items table. You'll be redirected to the edit action, which doesn't exist yet. Let's create it now. Here's the controller part (note the similarity between ItemsController#edit and ItemsController#create above):

      class ItemsController < ApplicationController
        def edit
          @item = Item.find(params[:id])

          if request.post?
            @item.update_attributes(params[:item])
            redirect_to :action => 'edit', :id => @item.id
         
    end
        end
      end

    In fact, the edit action is so similar to the create action that its form can be almost identical. The only differences are in the arguments to form_tag:

      <!-- app/views/items/edit.rhtml -->

      <%= form_tag :action => "edit", :id => @item.id %>
       Name: <%= text_field "item", "name"
    %><br />
       Value: <%= text_field "item", "value"
    %><br />
       <%= submit_tag %>
     
    <%= end_form_tag %>

    Discussion

    This is probably the most common day-to-day task faced by web developers. It's so common that Rails comes with a tool called scaffold that generates this kind of code for you. If you'd invoked generate this way instead of with the arguments given above, Rails would have generate code for the actions given in the Solution, plus a few more:

      $ ./script/generate scaffold Items

    Starting off with scaffolding doesn't mean you can get away with not knowing how Rails form generation works, because you'll definitely want to customize the scaffolding code.

    There are two places in our code where magic happens. The first is the text_field call in the view, which is explained in the Solution. It binds a member of an object (@item.name , for instance) to an HTML form control. If you view the source of the /items/new page, you will see that the form fields look something like this:

      Name: <input type="text" name="item[name]" value="" /><br />
      Value <input type="text" name="item[value]" value="[empty]" /><br />

    These special field names are used by the second piece of magic, located in the calls to Item.create (in new) and Item#update_attributes. In both cases, an Item object is fed a hash of new values for its members. This hash is embedded into the params hash, which contains CGI form values.

    The names of the HTML form fields (item[name] and item[value]) translate into a params hash that looks like this:

      {
       
    :item => {
         
    :name => "Name of the item",
         
    :value => "Value of the item"
       
    },
       
    :controller => "items",
       
    :action => "create"
     
    }

    So this line of code:

      Item.create(params[:item])

    is effectively the same as this line:

      Item.create(:name => "Name of the item", :value => "Value of the item")

    The call to Item#update_attributes in the edit action works exactly the same way.

    As mentioned above, the views for edit and new are very similar, differing only in the destination of the form. With some minor refactoring, we can remove one of the view files completely.

    A call to <%= form_tag %> without any parameters at all sets the form destination to the current URL. Let's change the new.rhtml file appropriately:

      <!-- app/views/items/new.rhtml -->
      <%= form_tag %>

      Name: <%= text_field "item", "name"
    %>&#x00A;
      Value: <%= text_field "item", "value"
    %>&#x00A;

      <%= submit_tag %>
      <%= end_form_tag %>

    Now the new.rhtml view is suitable for use by both new and edit. We just need to change the new action to call the create method (since the form doesn't go there anymore), and change the edit action to render new.rhtml instead of edit.rhtml (which can be removed):

      class ItemsController < ApplicationController
         def new
            @item = Item.new
             create if request.post? 
        
    end

         def edit
             @item = Item.find(params[:id])

              if request.post?
                 @item.update_attributes(params[:item])
                 redirect_to :action => 'edit', :id => @item.id and return
               end
               render :action => 'new'
          end
      end

    Remember from Recipe 15.5 that a render call only specifies the template file to be used. The render call in edit won't actually call the new method, so we don't need to worry about the new method overwriting our value of @item.

    In real life, there would be enough differences in the content surrounding the add and edit forms to a separate view for each action. However, there's usually enough similarity between the forms themselves that they can be refactored into a single partial view (see Recipe 15.14) which both views share. This is a great example of the DRY (Don't Repeat Yourself) principle. If there is a single form for both the add and edit views, it's easier and less error-prone to maintain that form as the database schema changes.

    See Also

    1. Recipe 15.5, "Displaying Templates with Render"
    2. Recipe 15.14, "Refactoring the View into Partial Snippets of Views"

    More Ruby-on-Rails Articles
    More By O'Reilly Media


       · This article is an excerpt from the "Ruby Cookbook," published by O'Reilly. We hope...
     

    Buy this book now. This article is excerpted from chapter 15 of the Ruby Cookbook, written by Lucas Carlson and Leonard Richardson (O'Reilly, 2006; ISBN: 0596523696). Check it out today at your favorite bookstore. Buy this book now.

    RUBY-ON-RAILS ARTICLES

    - Iterating and Incrementing Strings in Ruby
    - Comparing and Manipulating Strings in Ruby
    - Strings in Ruby
    - Ruby On Rails: Making Your First Dynamic Site
    - Ruby on Rails: Beginning Rails
    - Ruby: Modules, Mixins, Fixins, and Rails
    - Controlling Information Access with the Rail...
    - URLs, Filters and the Rails Action Controller
    - Flash and the Rails Action Controller
    - Rails Action Controller
    - Dropping and Sorting with AJAX and script.ac...
    - Drag and Drop with script.aculo.us and Rails
    - Introducing script.aculo.us
    - Ruby Classes and Objects
    - Ruby Loops







    © 2003-2009 by Developer Shed. All rights reserved. DS Cluster 2 hosted by Hostway
    Stay green...Green IT