Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Ride the Web Application Express with Ruby on Rails : Page 4

Looking for productivity improvements in your Web application development? Take a look at a Web application framework that takes fewer lines of code than words in this sentence to have your first application up and running.

The Magic Behind Rails
So how did this all happen with just one line of code change? In a word, it is metaprogramming. The model class you developed, or more precisely, generated from the script, inherits from Ruby on Rails' ActiveRecord class. ActiveRecord objects dynamically infer their attributes from the table definition that they are linked to and you linked the ContactType to the contact_type database table by using Rails naming conventions. Rails naming conventions work to bridge the plural/singular difference from a table containing many to a singular instance of the model. For example, note that the database table is contact_types while an instance of the model comes from ContactType class. Yep, Rails is smart enough to figure out that instances of ContactType should probably be stored in a contact_types database table.

Figure 9. Rails Immediately Reflects Change: Changes to the database are immediately reflecting in Rails models and views as a result of using the Rails framework. Here, a new column called new_column is added to contact_type and it is immediately reflected in the view with no restart or code changes.

The view and controller are no less remarkable in Rails. The ContactTypeController class generated by the Rails script descends from ActiveController. The one line of code you added to ContactTypeController added Rails "scaffolding" to the class. Scaffolding is a series of standard MVC-styled actions for listing, creating, reading/showing, updating, and deleting the model objects. In other words, it added typical CRUD functions to the controller to deal with ContactType objects. The scaffolding :contact_type code you added also gave the application default views through introspection to display and edit the fields of the model. In a bit, you will see how to override the default views and functionality provided by the controller, but for now sit back and enjoy the power of Ruby on Rails. While you are at it, also notice the URLs as you manipulate your way around the pages. Do they seem a little more intuitive? That, too, is on purpose. It makes building and operating Ruby on Rails Web sites a bit easier.

Also, because of the dynamic nature of the Rails ActiveController and ActiveRecord, changes in the database are automatically reflected. Return to your database table and add a new column. For example, I added a new column called new_column as shown in Figure 9. If you refresh your browser, the new column will display in all the appropriate views—without even restarting the server or application.

Overriding Defaults
Admittedly, more complex Rails applications are going to require more than one line of code to get them up and running. But with the default behavior in place, much of the code you write is to override the default behavior provided by Rails components.

For an example of overriding default behavior in Rails, modify the Web site you've created to remove the ability to delete contact types. Contact types are reference data for the soon-to-be-developed contacts application. If they were removed, then any contacts would reference an unknown contact type.

To begin, open the contact_type_controller.rb file in the rolodex\app\controllers folder. Add a new and empty implementation of the destroy method in your ContactType controller. The code, when complete, should look like that displayed below.

class ContactTypeController < ApplicationController scaffold :contact_type def destroy end end

With this code in place, return to your browser and attempt to delete or "destroy" one of the contact types. You will be greeted with the error message displayed in Figure 10.

Figure 10. Attempt to Delete: With the destroy method overridden in the ContactTypeController, destroying contact types no longer works and this error message is displayed.

The destroy method you provided overrides the default destroy method that Rails' scaffolding framework provides. The default method also uses a dynamically generated and provided "template" or view. So, when you override the default behavior in a Rails controller, you must also provide a new view.

To correct the current error of a missing template, go to the rolodex\app\views\contact_type folder. In this directory, you will create a new view for the destroy functionality which you wish to override. Ruby on Rails uses HTML tagging that looks and behaves like Java Server Pages (JSP) or Active Server Pages (ASP). Create a new page called destroy.rhtml—notice the .rhtml file suffix. Enter the code shown below.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Ruby Rolodex</title> </head> <body> <h1>Removing contact types is not allowed</h1> <a href="/contact_type/list">Back</a> </body> </html>

Other than formatting the response a little neater, this code does nothing, and that's the point. When the user attempts to destroy a contact type, they are told they can't do this. Also within the HTML code, notice the reference link that directs the user back to the contact type list page when clicked. Again, the Ruby on Rails URLs are simple and straightforward. Referencing or redirecting to them is easy to do—for both you and your users.

This is nice, but you probably also want to just remove the Destroy option on the contact type list view itself. For this, you need to also override the default list view of contact type. Create another page, list.rhtml, in the rolodex\app\views\contact_type folder. The code for this page is below:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Ruby Rolodex</title> </head> <body> <h1>Contact Types</h1> <table border="1"> <tr> <th>Name</th> <th> </th> </tr> <% @contact_types.each do |contact_type| %> <tr> <td><%= link_to contact_type.name, :action => "show", :id => contact_type.id %></td> <td><%= link_to "edit", :action => "edit", :id => contact_type.id %></td> </tr> <% end %> </table> <br /> <a href="/contact_type/new">Add a new contact type</a><BR> </body> </html>

Figure 11. Overriden List and Delete Pages: With the appropriate Rail scaffolding controller methods and template views overridden, destroying a contact type is no longer visible and no longer possible even if the user knows the appropriate URL.

Again, this page helps to pretty up the default view, but it also removes the default CRUD behavior by removing the delete behavior. The <% %> and <%= %> tags allow Ruby code to be embedded in the HTML pages. The embedded Ruby code loops over a list of contact types. The code is making use of the instance variable @contact_types for the list of contact types. In the list method on the controller, the default behavior is to set this instance variable to the set of associated model objects, which, in this case, is a collection of ContactType objects. The link_to method calls create HTML references which take the user to the default show and edit pages for contact types and pass the appropriate contact type id to the controller to use to populate the page with data.

Return to the browser and try the Web application again. The "destroy" option is no longer available, but if a smart user attempts to call on the appropriate default scaffolding by entering http://localhost:3000/contact_type/destroy/<some contact type id>, the appropriate message is displayed (see Figure 11).

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.