Home arrow Ruby-on-Rails arrow Page 2 - Validating Author Data in an Online Bookstore

Validating Author Data in an Online Bookstore

In this third part of a four-part article series on building an online bookstore application with Ruby on Rails, you'll learn how to actually create authors in the system, validate data, and more. This article is excerpted from chapter two of the book Practical Rails Projects, written by Eldon Alameda (Apress; ISBN: 1590597818).

Author Info:
By: Apress Publishing
Rating: 5 stars5 stars5 stars5 stars5 stars / 1
May 13, 2010
  1. · Validating Author Data in an Online Bookstore
  2. · Creating the Author
  3. · Validating Data
  4. · Listing Authors

print this article

Validating Author Data in an Online Bookstore - Creating the Author
(Page 2 of 4 )

The next thing to do is to actually create the author. For this, we use thecreate action, where the form on thenewpage is pointing. What we want from the create functionality is that when we post a form to thecreateaction, a new author is created according to the parameters we specify. Let’s extend our tests to test for this, too, by adding a new test case method.

def test_create
  assert_equal 0, Author.find(:all).size
  post :create, :author => {:first_name => 'Joel',
                              :last_name => 'Spolsky'}
  assert_response :redirect
  assert_redirected_to :action => 'index'
  assert_equal 1, Author.find(:all).size
  assert_equal 'Author Joel Spolsky was successfully created.', flash[:notice]


Flash (http://api.rubyonrails.org/classes/ ActionController/Flash/FlashHash.html) is a clever mechanism in Rails (having nothing to do with Adobe/Macromedia Flash) for sending user notices and
error messages from page to page. When we, for example, create a new author, it is a good idea to show the user a notice that the author was indeed created.

Flash is a hash-like structure stored on the server for the time of one sequential action. It is available in
both controllers and views. So when we set flash[:notice] in the create action and then redirect to the index action, the index page has access to the notice. If the user then clicks a link and goes on to another page, the notice has disappeared from the flash and the notice is not shown anymore.

If you sometimes want to show a flash message in the current action so that it will not be available in the next action (for example, when a form input has been invalid and you want to rerender the form instead of redirecting to the next action), you should use flash.now instead of flash. It will cause the message to be
cleaned up immediately after the current action has been processed.

Here, we first test that there are no authors in the test database. Then we try to create a new author by simulating the HTTPPOST method sending a form to thecreate action. We expect that Rails responds to thePOSTrequest by redirecting us to the index page. We also want to make sure that a newAuthor object is created and that Rails sets theflash[:notice]variable correctly.

However, the test code is not really beautiful. Instead of checking the exact amount of authors before and after running thecreateaction, we only want to know that the amount was incremented by one. Fortunately, the chaps at projectionist (http://project.ioni.st/) have created a helper assertion method for testing just that (http://project.ioni.st/post/218#post-218). Opentest/test_helper.rbin a text editor and add the following code to it:

def assert_difference(object, method, difference=1)
initial_value = object.send(method)
assert_equal initial_value + difference,

def assert_no_difference(object, method, &block)
assert_difference object, method, 0, &block

Tip  test/test_helper.rbis a file where you can define helper methods that are available to all tests. A helper method can be a custom assertion like above, or any other method that makes writing actual tests easier and cleaner.

assert_differencetakes as its parameters an object, a method of that object, and a code block. It first stores the initial value returned byobject.method, then runs the code block, and after that fetches the return value ofobject.methodagain. If the difference between those two method calls is not exactly the value of thedifference parameter (1by default), the test will fail.assert_no_differenceis a convenience method that callsassert_differencewith thedifferencevalue of zero.

Now we can change the code intest_createto the following:

def test_create
get :new
assert_template 'admin/author/new'
assert_difference(Author, :count) do
post :create, :author => {:first_name => 'Joel',
:last_name => 'Spolsky'}
assert_response :redirect
assert_redirected_to :action => 'index'

assert_equal 'Author Joel Spolsky was successfully created.', flash[:notice]

Now, instead of explicitly checking the number of authors before and after the request, we enclose it inside anassert_differencecall. And because the default value of thedifferenceparameter is1,assert_differencepasses if, and only if, the code inside its code block increments the count of authors by one. It doesn’t matter what the value was before, so we’re not relying on theauthorstable being empty at the start anymore.

Running the test obviously fails, so let’s move on to implement the author creation. We have an emptycreateaction inauthor_controller.rb, so we can go ahead and fill it in.

def create
@author = Author.new(params[:author])
if @author.save
flash[:notice] = "Author #{@author.name} was successfully created."
redirect_to :action => 'index'
@page_title = 'Create new author'
render :action => 'new'

Thecreateaction is a typical example of how actions that modify data work in Rails. First, we create a newAuthorobject from the request parameters sent from the form on thenewpage. Then we try to save the object. If the object was valid and could thus be saved, we create a flash message to be shown to the user and redirect to a page that lists all the authors. If@authorcouldn’t be saved—probably because it didn’t pass the validations (we’ll talk more about validations in the next section)—we render thenew.rhtmltemplate with the form again, so that the user can fill in the required fields she forgot to fill in the first time.

Running the test again, we see that it passes. But George has also advised us that every author needs to have both a first and a last name. We thus want to test that no new author is created if either of those form fields is left empty. We create another test method for this intest/functional/admin/author_controller_test.rb:

def test_failing_create
  assert_no_difference(Author, :count) do
    post :create, :author => {:first_name => 'Joel'}
    assert_response :success
    assert_template 'admin/author/new'
assert_tag :tag => 'div', :attributes => {:class => 'fieldWithErrors'} 

Here, we do the same thing as in the previous test, except that this time, we leave the last name out of the form post. Now, instead of a redirect, we want Rails to show us the form template again, with the fields with errors marked accordingly. We also useassert_no_differenceto make sure that the new author is not created.

When we run the test, we can see it failing. Instead of rendering the form again on an invalid form input, we are still redirected to the index page. We need a way to make the form validate only if both the first and the last name are present. In Rails, validations are done on the ActiveRecord object level.

blog comments powered by Disqus

- Ruby-on-Rails Faces Second Security Flaw in ...
- Ruby 2.0 Prepped for February 2013 Release
- Why LinkedIn Switched from Ruby on Rails
- Adding Style with Action Pack
- Handling HTML in Templates with Action Pack
- Filters, Controllers and Helpers in Action P...
- Action Pack and Controller Filters
- Action Pack Categories and Events
- Logging Out, Events and Templates with Actio...
- Action Pack Sessions and Architecture
- More on Action Pack Partial Templates
- Action Pack Partial Templates
- Displaying Error Messages with the Action Pa...
- Action Pack Request Parameters
- Creating an Action Pack Registration Form

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 

Developer Shed Affiliates


© 2003-2019 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials