Rails vs. Grails vs. Helma: The JVM Web Framework Smackdown, Part 1

It's the ultimate JVM Web Framework Smackdown! Three will enter the cage. Only one will exit the victor. Will it be JRuby on Rails? Groovy on Grails? Or Helma?

Rails Views

Rails uses .erb files for its views; a .erb contains HTML with embedded Ruby code, a format similar to scriptlets in JSPs. <%=…%> outputs a value, whereas <%…%> does not. The latter is largely used for control structures.

The view layer is both a strength and weakness of Rails. It is easy to use, and since there is no alternative to embedded code, you need not feel particularly guilty about its use. With the clean structure that Rails offers, code embedded in the view tends to be view-related code.

Nonetheless, ugly is still ugly. Embedded code makes the views awkward for web designers, and there is a constant risk of non-view-related code seeping in where it does not belong. Of all the frameworks, Rails’s views end up the poorest looking.

On the other hand, Rails does deserve credit for a couple of features, most notably partial rendering (nicknamed “partials”) and layouts. Partial rendering allows a developer to reuse an HTML chunk that reoccurs in different pages. (While it is a nice feature, it’s not needed in this application.) Layouts, in contrast, are used heavily in almost every Rails project.

For those not familiar with layouts, the concept is simple. For many applications, you may have a standard header and footer, possibly even a left or right rail that you wish to be shared across all your pages. There are other approaches, but none seems to solve this issue as cleanly as Rails’s layouts. Here is a sample for PenguinMusic found in app/views/layouts/main.html.erb:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title><%= @title || "PenguinMusic" %></title>
  <%= stylesheet_link_tag 'main' %>
  <%= stylesheet_link_tag 'scaffold' %>
</head>
<body>
<div id="outer">
  <div id="header">
    <div id="toolbar">
        <%= link_to "Home", :controller=>'songs', :action=>'popular', :id=>0 %>
    <% if !session[:user] %>
      | <%= link_to "Login", :controller=>'users', :action=>'login', :id=>0 %>
      | <%= link_to "Register", :controller=>'users', :action=>'register', :id=>0 %>
    <% else %>
      | <%= link_to "Logout", :controller=>'users', :action=>'logout', :id=>0 %>
    <% end %>
      | <%= link_to "FAQ", :controller=>'misc', :action=>'faq' %>
    </div>
  </div>
  <hr />
  <p style="color: green"><%= flash[:notice] %></p>
  <div id="body">
    <%= yield %>
  </div>
</div>

</body>
</html>

The <%= yield %> towards the bottom of the document is where page-specific content is collected and emitted. You might also be wondering about the <%= flash[:notice] %>. The flash is a hash whose contents are available for the next request in the session. After that, it is automatically emptied. This makes it an ideal tool to display messages to the user.

To use this layout, you must modify the controllers, the final piece of the MVC architecture.

Controllers

For a Rails application, there is a central controller for the application itself. However, you generally do not make many modifications to it. Instead, you create different controllers for different pieces of your application. For the most part, each controller correlates to a model. If you generated scaffolding for each model in our music store application, you should now have seven controllers. Let’s generate one more:

$ jruby script/generate controller misc

This generates a new MiscController object, which will be useful for adding in actions that don’t fit in neatly elsewhere. For example, many applications have an FAQ page;
the music site does as well. To add the FAQ page, let’s add an action to the MiscController and a new .erb file to the collection of views. The .erb file is standard HTML. The controller is therefore not much more complicated. Here it is in its entirety:

class MiscController < ApplicationController
  layout "main"
    
  def faq
  end
end

As mentioned before, the layout to use must be named within the controller. The line layout "main" accomplishes this. With no more work, the FAQ page now has the same header as the rest of the application.

Of course, this controller is not terribly interesting. How does Rails deal with a more complex piece of code? Let’s examine the controller needed for the “most popular songs” page.

class SongsController < ApplicationController
  layout "main"
  
  def popular
    @genres = Genre.all
    @songs = Song.all :order=>"num_downloads"
    
    @genre_id = params[:genre]
    if (@genre_id)
      @new_songs = []
      @songs.each do |song|
        if song.album.genre.id.to_s == @genre_id
          @new_songs.push song
        end
      end
      @songs = @new_songs
    end
    
    @num_songs = @songs.size
    @start_ind = (params[:start] || 0).to_i
    @page_size = (params[:size] || 20).to_i
    
    @songs = @songs.slice @start_ind, @page_size
    
    @featured = []
    ["hipcitycruz", "namelyus", "markgrowden"].each do |code|
      @featured.push Album.find_by_public_id code
    end
  end
  ...

The popular() method generates the various collections required to render the page. (It also sets up pagination, which is discussed momentarily.) Since the method name is “popular”, Rails looks for the corresponding view in app/views/songs/popular.html.erb.

<div id="left_rail">
  <% @featured.each do |album%>
    <div class="featured-album">
      <em><%= album.artist.name %></em><br />
      <strong><%= album.title %></strong><br />
      <% link_to image_tag("/albumArt/" + album.album_cover_name),
          :controller=>'album', :action=>'display', :id=>album.id %>
      <a href="/albums/display/<%= album.id %>">
        <img width="150" height="150" src="/albumArt/<%= album.album_cover_name %>" />
      </a>
      <br /><br />
    </div>
  <% end %>
</div>
<div id='genres'>
  <% @genres.each do |genre%>
  <div class="genre-link<%= ' genre-selected' if @genre_id == genre.id.to_s %>">
    <%= link_to genre.name,
        {:controller=>'songs', :action=>'popular', :id=>0, :genre=>genre.id} %>
  </div>
  <% end %>
  <div class="genre-link<%= ' genre-selected' unless @genre_id %>">
    <%= link_to "All genres",
        {:controller=>'songs', :action=>'popular', :id=>0} %>
  </div>
</div>
<br /><br />
<div id="most_popular">
  <h1>Most Popular</h1>
  <table border="0" cellspacing="5" cellpadding="5">
    <th>Song</th><th>Band</th><th>Album</th>
    <% @songs.each_with_index do |song,i%>
    <tr class="<%= if(i%2 == 0) then "odd-row" else "even-row" end %>">
      <td><a href="<%= song.playlist_url %>"><%= song.name %></a></td>
      <td><em><%=
        link_to song.album.artist.name,
            :controller=>"artists", :action=>"display", :id=>song.album.artist
      %><!--a href="<%= song.album.url %>"><%= song.album.artist.name %></a--></em></td>
      <td><strong><%=
        link_to song.album.title, :controller=>"albums", :action=>"display", :id=>song.album
      %></strong></td>
    </tr>
    <% end %>
  </table>
  <hr />
  <%
  i=0
  while i<@num_songs do
  %>
    <%=
      if (i!=@start_ind)
        link_to (i/@page_size + 1).to_i, :action=>"popular", :id=>0, :start=>i, :genre=>@genre_id
      else
        (i/@page_size + 1).to_s
      end
    %>
  <%
    i += @page_size
  end
  %>
</div>

User Authentication

For another example, consider user authentication. Rails already has some plugins to deal with the problem, but let’s create a solution to explore how the feature typically works. At the end of app/controllers/users_controller.rb, add an authorize() method:

  ...
  private

  def authorize
    unless session[:user]
      flash[:notice] = "Please log in to view that page"
      redirect_to :action => "login", :id=>0
    end
  end
end

authorize() can check that a user is logged in before accessing certain pages. By itself, however, it does nothing. To call the method automatically, you must add a before_filter. This code adds both the filter and the actions needed:

require 'digest/md5'

class UsersController < ApplicationController
  layout "main"

  before_filter :authorize, :except => [:login, :login_user]
  
  def login
    @user = User.new
  end
  
  def login_user
    tmp = User.new(params[:user])
    @user = User.find_by_username tmp.username
    if @user && @user.password == Digest::MD5.hexdigest(tmp.username + tmp.password)
      flash[:notice] = "Welcome, #{@user.username}"
      session[:user] = @user
      redirect_to :controller=>'songs', :action=>'popular', :id=>0
    else
      render :action=> 'login', :id=>0
    end
  end
  ...

With these additions, any attempt to access a users/* page redirects the user to login, unless the user is already logged in to the application. Of course, in a real example, this would be more complex—different pages would require different levels of access.

The application is not done yet, however. The actions exist, but the view is missing. Let’s look at Rails’s facilities for handling forms.

Form Handling

Forms are one of the nastier bits of Web applications. Rails makes it very easy to handle forms that correspond directly to an object. Here is the view for the login page:

<h2>Login to PenguinMusic</h2>

<% form_for(:user, :url=>{:action=>'login_user'}) do |f%>
  <%= f.error_messages %>

  <p>
    <%= f.label :username %><br />
    <%= f.text_field :username %>
  </p>
  <p>
    <%= f.label :password %><br />
    <%= f.password_field :password %>
  </p>
  <p>
    <%= f.submit 'Login' %>
  </p>
<% end %>

Things get a little more complex for extra fields. For example, a form to register users commonly has a password verification field. This would use a slightly different syntax:

  ...
  <p>
    <%= f.label :password_verification %><br />
    <%= password_field_tag :password_verification, '', :size=>30 %>
  </p>
  ...

The different syntax is a little confusing at first. You do get used to it quickly enough, but it is one of the more awkward stumbling blocks.

Comments on "Rails vs. Grails vs. Helma: The JVM Web Framework Smackdown, Part 1"

gigo6000

If you like PHP and MVC you can use symfony, it\’s a great framework pretty much like RoR

Reply
cdhutch

The \”perl = spaghetti-code\” myth is a little outdated. Modern perl web frameworks like Catalyst and Mojolicious, and the long-established HTML::Mason are widely used.

Reply
ftudone

Well… There\’s at least another very worth considering one, a Scala one and that\’s Lift: http://liftweb.net

Reply

Definitely would love to start a website like yours. Wish I had the time. My site is so amateurish compared to yours, feel free to check it out: http://tinyurl.com/o55af8p Alex :)

Reply

Wonderful beat! I must novice even though you modify your internet site, how may possibly my spouse and i signed up for any web site site? This bill taught me to be any relevant cope. I’ve been little bit comfortable of your ones transmitted offered sparkling clear idea

Reply

Blog looks nice. I’m still trying to make a blog but it won’t be as professional as yours /: Keep on blogging :) pirater un compte facebook

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>