 |
Brian Leonard's Blog
Brian Leonard works as a senior software engineer with Sun Microsystems. He's been working with application servers before there was a J2EE standard, helping develop applications as well as the servers that run them. Until most recently, Brian's been focused on helping large enterprises implement and deploy highly-available architectures. In his current role, Brian is an evangelist for the NetBeans open source IDE.
Drag & Drop with Rails
Posted by bleonard on April 18, 2008 at 11:45 AM | Permalink
| Comments (0)
The ability to drag and drop has been a staple of desktop applications for years. With the advent of Ajax, the ability to drag and drop has now found its way to web applications. In this entry I spice up the blogging application we've been building with the ability to drag comments to the trash. This is an appropriate feature to add as our own blogs here on java.net have been prone to spam attacks via the comments which require cleanup.
Setting Things Up
I'm going to continue from where the tutorial Using Ajax with Ruby on Rails leaves off. However, I'll be using NetBeans 6.1 and Rails 2.0, so you may want to start with this updated version of the rubyweblog project which has been updated to Rails 2.0 (the entire tutorial series is in the process of being updated).
Test the Existing rubyweblog Project
- Open the rubyweblog project.
- Note, if you are starting with the provided rubyweblog project, you will also need to create the rubyweblog_development database (Run Rake Task > db > create) and run the migrations.
- Run the project and browse to http://localhost:3000/posts to verify that it works. Add at least one blog entry with a couple of comments.
The Plan
Currently, the application does not provide the means to delete a comment. Now, I know this application is severely lacking any sort of user model or administrative interface, but my intent is to show how to do cool things with Rails, not create a replacement for roller, so I squeeze the features in where I can. In this case, I'm going to add a trash can icon to the page and allow users to drag comments to the trash for deletion.
Step 1: Make the Comments Draggable
Here we'll employ the draggable_element helper, a Rails wrapper around the Scriptaculous Draggable object, to make the comments draggable.
- Open _comment.html.erb, which is the partial for displaying a single comment, and make it draggable by adding the draggable element helper to the bottom of the file as shown in bold below:
<% comment_id = "comment_#{comment.id}" %> <li id=<%= comment_id %> > <%= h comment.comment %><br> <div style="color: #999; font-size: 8pt"> Posted on <%= comment.created_at.strftime("%B %d, %Y at %I:%M %p") %> </div> </li> <%= draggable_element(comment_id, :revert=>true) %>
Note, since comment_id is used twice, I pulled it out into a local variable to keep the code a bit cleaner. Revert returns the comment to its original location if we drop it anywhere but on the trash can (which we haven't added yet).
- Add a visual indicator that the comments are draggable. Open scaffold.css (Public > stylesheets) and add the following style:
#comments { cursor: -moz-grab; }
- Test your changes. The comments are now draggable, but we haven't specified anywhere to drop them yet.
Step 2: Add the Trash Icon
- Save
(trashfull.jpg) to the public/images directory of your rubyweblob project directory.
- Open show.html.erb and add the following <image_tag> after the <text_area>:
<%= text_area 'comment', 'comment' %> <%= image_tag "trash.jpg", :id=>'trash'%>
Step 3: Make the Trash Icon a Drop Receiver
Here we'll use the drop_receiving_element helper, a Rails wrapper around the Scriptaculous Droppables.add method to give the comment a drop destination and call the action to delete the comment.
- Open show.html.erb and add the drop_receiving_element to the bottom of the file as show below:
<%= drop_receiving_element('trash', # The id of the receiving element :accept => "comment", # The CSS class of the dropped element :with => "'comment=' + (element.id.split('_').last())", # The query string parameters :url => {:action=>:trash_comment} # The action to call )%>
Note the :with parameter - this is a piece of JavaScript code that extracts the comment ID form the DOM ID, which if you recall from above is something like "comment_123". We also still have some work to do: first, we don't have anything with a CCS class named "comment" and second we need to code the trash_comment action.
- Open _comment.html.erb and add class="comment" to the <li> tag:
<li class="comment" id=<%= comment_id %> >
- Open posts_controller.rb and add the following trash_comment action:
def trash_comment comment_id = params[:comment] Comment.delete(comment_id) render :update do |page| page.replace_html "comment_#{comment_id}", "" end end
- Test your changes. Dragging a comment to the trash can should delete it and clear it from the list, although the bullet still remains. That's because the replace_html method above is replacing the html inside of the bulleted list item. Wrapping the bulleted list items in a <div> solves this problem.
- Open _comment.html.erb and wrap the <li> in a <div>, also moving the class and id properties to the <div>:
<% comment_id = "comment_#{comment.id}" %> <div class="comment" id=<%= comment_id %> > <li> <%= h comment.comment %><br> <div style="color: #999; font-size: 8pt"> Posted on <%= comment.created_at.strftime("%B %d, %Y at %I:%M %p") %> </div> </li> </div> <%= draggable_element(comment_id, :revert=>true) %>
- Now the comments should delete completely.
Step 4: Adding Visual Clues That Something's Happening
- Save
(trashfull.jpg) to the public/images directory of your rubyweblob project directory.
- Add a couple of JavaScript methods to show.html.erb to swap the source of the trash image from empty to full and back:
<script> function fill_trash() { $('trash').src = "/images/trashfull.jpg"; } function empty_trash() { $('trash').src = "/images/trash.jpg"; } </script>
- Add a couple of properties to the drop_receiving_element method, :onHover and :complete:
<%= drop_receiving_element('trash', # The id of the receiving element :accept => "comment", # The CSS class of the dropped element :with => "'comment=' + (element.id.split('_').last())", # The query string parameters :url => {:action=>:trash_comment}, # The action to call :onHover => "function() {fill_trash()}", :complete => "empty_trash()" )%>
Note, I can't tell you why :onHover requires a function definition while :complete takes any arbitrary JavaScript, but that's the way it works.
- Test your changes. You should now see a full garbage can when you drag a comment over it and then empty again once the delete completes.
- There's still one minor problem - if you drag a comment over the trash but don't actually drop it, your trash can remains full. We can fix this using the onMouseOut event. Add it to the image_tag as follows:
<%= image_tag "trash.jpg", :id=>'trash', :onMouseOut=>"empty_trash()"%>
And that should pretty much complete the drag and drop functionality. Remember to refresh the browser to pick up changes to Javascript. Also, Firebug is your friend whenever you're working with Ajax and not seeing what you're expecting.
The Completed Application
RubyWeblogDND.zip
Autovalidation with Rails
Posted by bleonard on April 16, 2008 at 12:31 PM | Permalink
| Comments (0)
Actually, I don't know what this feature is called, but I love it when a web application gives me instant feedback on the validity of my entry. For example:

This is especially true when I'm registering a new user account - submitting the page over and over again because the username I've selected is already taken or the password doesn't meet the requirements is always a drag.
So I started looked for examples on how to do this in Rails and couldn't really find anything (possibly because I don't actually know what to call it) - I guess it's most similar to autocompletion, so I'm going with autovalidation. And here are the steps I've put together to get it to work...
Setting Things Up
- Download and install MySQL.
- Download and install NetBeans 6.1 RC1 or later.
Creating the Rails Project
- Create a new Ruby on Rails Application named autovalidation. You can select Finish after the first page of the New Ruby on Rails Application dialog:

- Right-click the project and select Run Rake Task > db > create:

- Right-click the project and select Generate. Generate a scaffold with the Model Name User and the Attribute Pairs username:string:

- Right-click the project and select Migrate Database > To Current Version.
- Open user.rb and type the following:
vu[tab]
- this will expand to:

type username over the attribute and press enter.
- On the next line in user.rb type the following:
vl[tab] this will expand to:

type username over the attribute and press enter. Type 5..10 over the 3..20 and press enter. The completed code should look as follows:
class User < ActiveRecord::Base
validates_uniqueness_of :username
validates_length_of :username, :within => 5..10
end
Traditional Server Side Validation
- Run the project and browse to http://localhost:3000/users. Try to create a new user such as bill:

- Okay, create william.
- Try to create william again:

Let's enhance this application with more user friendly "autovalidation"...
Lets Autovalidate
In addition to the server side validation that's being performed, we're going to add some client side validation using Ajax. We'll do this by displaying a message to the right of the field on the validity of what's been entered. Since we're validating against the database, we will need to make an XMLHTTPRequest back to the server. We can use Rails' observe_field helper method for this task.
- First we need to create a named placeholder for the message. Open new.html.erb and add a <span> tag after the text field as follows:
<%= f.text_field :username %><span id="message"></span>
- Now we'll use Rails' observe_field method to watch changes to that field. Add the following before the closing <% end %> tag:
<%= observe_field :user_username, # The field to observe :with => "username", # The input to validate :frequency => 0.25, # The frequency in seconds to watch for changes :url => {:action => :validate }, # The action to call when changes occur :update => :message # The DOM ID to update %>
- Create the validate action. Open users_controller.rb and add the following:
def validate color = 'red' username = params[:username] if username.length < 5 message = 'Too short' elsif username.length > 10 message = 'Too long' else user = User.find_all_by_username(username) if user.size > 0 message = 'Taken' else message = 'Available' color = 'green' end end @message = "<b style='color:#{color}'>#{message}</b>" render :partial=>'message' end
You'll notice in the last line of the validate action above we're rendering a partial. This partial, which we'll create next, will be dynamically rendered inside the span tag we defined in step 1 above.
- Create a new ERB file named _message in Views > users. Replace its contents with the following:
<%= @message %>
- Open users.html.erb and add the following before the closing </head> tag:
<%= javascript_include_tag 'prototype' %>
All Rails applications come with the prototype and scriptaculous libraries ready to use, but you do need to tell the application that you want to use them.
Run with Autovalidate
- Switch to the browser and start creating a new user (you'll need to refresh the browser once to load the prototype JavaScript libraries):




Troubleshooting
Firebug is your friend for troubleshooting Rails applications. With Firebug enabled, you can see the requests as you type:
A couple of things that tripped me up
Forgetting to include the Prototype libraries:

Misspelling the field to observe:

The Completed Application
autovalidation.zip
Blogging for Dollars (and T-Shirts)
Posted by bleonard on March 18, 2008 at 11:37 AM | Permalink
| Comments (0)
The NetBeans team has started a blogging contest. Simply download the NetBeans 6.1 Beta and tell us your thoughts. What, you're not a blogger? Well, here are some places to get started:
See the blogging contest web site for details on how to enter, ideas for your blog, rules and deadlines.
Hello Grails!
Posted by bleonard on January 30, 2008 at 06:37 PM | Permalink
| Comments (19)
NetBeans 6.1 M1 was just released, and with it comes rudimentary support for the Groovy language and the Grails framework. I say rudimentary because this is M1, but there's a lot of work in progress as you can see from this task list.
So, of course I'm anxious to compare Grails to Rails. What better way to do than by creating the same blog application I've been blogging about with Rails?
Setting Things Up
Unlike with Rails, the NetBeans Groovy plugin does not come bundled with Groovy and the Grails framework - these must be pre-installed on your system (don't worry, it's easy):
- Download and install Groovy
- Download and install Grails
- Download and install NetBeans 6.1 M1.
- Install the Groovy and Grails plugin (Tools > Plugins > Available Plugins)
- Open the NetBeans Options dialog and select the Groovy category. Set the Groovy and Grails home directories.
Creating the Grails Project
- Choose File > New Project to create a new Grails Application named GroovyWebLog. Your new Grails application will appear in the IDE:

Creating the Model
Or as Grails prefers to call them, Domain classes.
- Right-click the Domain classes node and select "Create new Domain Class":

- Name the class Post.
- When Post.groovy opens in the editor, add a single field, title:
class Post {
String title
}
Creating the Controller
- Right-click the Controllers node and select "Create new controller"
- Name the controller Blog.
- For now, we'll use dynamic scaffolding to create the application views at runtime. Replace the default contents of BlogController with the following:
class BlogController {
def scaffold = Post
}
Note, if our controller named matched the domain class name, we could then use def scaffolding = true. I kept the model and controller names different to match what we did with Rails.
Run the Application
- Right-click the GrailsWebLog project and select Grails > Run Application.
- If all goes well, NetBeans will start the Jetty server that comes bundled with Grails and launch your browser where you will see the Grails welcome page:

- Click the BlogController link:

- Create a New Post:

It's not immediately obvious, but the Id is a link which you can use to view the post details. From the detail page you can then edit and/or delete the post:

Adding Another Field
Our blog needs a body field.
- Edit Post.groovy and add a body field:
class Post {
String title
String body
}
- Return to the browser and depending on what you do, you may get an error. By default Grails is configured to drop and create the database every time a change is made, so if you tried to edit the existing record you were viewing, you got a NullPointerException. However, if you navigate back to the list, you will see that the body field has been detected and you can add a new record again:

A Friendlier Database Configuration
Surprisingly, we haven't had to talk about databases yet as the Grails framework magically took care of this for us. The Grails framework includes HSQLDB and all of the necessary configuration was setup for us in DataSource.groovy, which you'll find under the Configuration node:

You can also see from this configuration file that Grails supports the same three environments as Rails: development, test and production. It's also easy to switch to another database, just set the driver class name, jdbc url and copy the JDBC driver to the project's lib directory.
Do the following:
- Change the dbCreate property from "create-drop" to "update".
- Right-click the GrailsWebLog project and choose Grails > Stop Application.
- Richt-click the project again and choose Grails > Run Application.
- Now experiment with adding and/or deleting fields - you'll notice that the behavior is much more "Railsesque".
Validating Input
Like Rails, validation in Grails is very straightforward.
- Open Post.groovy and add the following constraints:
class Post {
String title
String body
static constraints = {
title(blank:false)
body(blank:false)
}
}
- Attempt to add a new Post without entering any data:

Customizing the View
Okay, enough with this dynamic scaffolding. Let's generate our controller and view code. Unfortunately, for this step I haven't found the menu option in NetBeans yet, so we'll resort to the command line for now.
- Open your command prompt and navigate to the GrailsWebLog project directory. If you've forgotten where this is, you can find it in the project's Properties dialog.
- Run the command grails generate-all Post:

- Now this created a new controller named PostController. I don't see a way to specify a controller name when using generate-all (or generate-controller). That's fine - I'll leave BlogController to do the dynamic scaffolding and use PostController for my customizations.
- Also created were a set of GSP (Groovy Server Pages) for managing the view for the PostController:

- Open list.gsp and delete everything from from the <h1>Post List<h1> to the </div> following the pagination buttons. In its place put the following:
<h1>The Groovy Blog</h1>
<g:each in="${postList}" var="post">
<h2>${post.title}</h2>
<p>${post.body}</p>
<small><g:link action="show" id="${post.id}">permalink</g:link></small>
<hr>
</g:each>
- Return to the browser and refresh the list page:

- To display the blog with the most recent entry first, add .reverse() to the end of postList in list.gsp:
<g:each in="${postList.reverse()}" var="post">

The Completed Application
GrailsWebLog.zip
 |
 |
April 2008
| Sun |
Mon |
Tue |
Wed |
Thu |
Fri |
Sat |
| |
|
1 |
2 |
3 |
4 |
5 |
| 6 |
7 |
8 |
9 |
10 |
11 |
12 |
| 13 |
14 |
15 |
16 |
17 |
18 |
19 |
| 20 |
21 |
22 |
23 |
24 |
25 |
26 |
| 27 |
28 |
29 |
30 |
|
|
|
Search this blog:
Categories
Community
Community: Java Enterprise
Community: Java Tools
Community: Mobile & Embedded
Community: NetBeans
J2EE
Web Applications
Archives
April 2008
March 2008
January 2008
December 2007
September 2007
August 2007
July 2007
June 2007
April 2007
March 2007
January 2007
December 2006
November 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
September 2005
August 2005
July 2005
June 2005
April 2005
March 2005
February 2005
Recent Entries
Drag & Drop with Rails
Autovalidation with Rails
Blogging for Dollars (and T-Shirts)

|