
|
Ruby on Rails WebAlbumThis tutorial discusses a few observations, and some improvements made to the WebAlbum application developed using Ruby on Rails 2.0.2 for a programming course I held between January and March, 2008. You'll need to install Ruby on Rails – version 2.0.2. The application also uses RMagick and SQLite. Installing RMagick is explained in this FAQ, this tutorial uses version 2.0.0. Installing SQLite is explained in this How-to, and the tutorial uses the Ruby SQLite3 wrapper version 1.2.1. The Ruby on Rails Wiki page also gives helpful information for SQLite.
Not all of the modifications were a total success, nonetheless I have documented those as well. I can't sell mistakes as a consultant, but I can at least learn from them.
The Original TutorialThe original application was explained in the programming course during two lessons, each two hours long. I won't go over the details again here, but you can take a look at the articles I wrote in Ruby on Rails, Part 1, and Ruby on Rails, Part 2. You can also check out the entire course, there is also a PDF available.
The application itself is relatively straightforward, there are users, who have albums, which contain pictures, that are actually a small set of images. Only the respective users can change albums and pictures, but all the information is available to the casual visitor. Lightbox was used to produce a slide show effect for the images.
My first impressions were that Ruby on Rails 2.0 is a definite improvement on the previous 1.2 version, even though this has caused some major breakages. The learning curve is gradual, as each problem presented itself I could reference the Wiki or the API, and almost always find the answer I was looking for. Otherwise Googling “ruby on rails api something” would usually find a relevant article.
My second impressions were that some things could be improved. While I had more or less followed the guidelines developing the models, controllers and views, there remained a few points that I was not happy with. Some of this unhappiness lay within my own code, and some was in the Rails generated code.
Of course some mistakes were due to ignorance. Rails can achieve a lot of things for you – if you know what's there. The trouble is that developers outside the Rails project, such as myself, don't have that much time to study all the details – we're too busy, er, writing code.
Unhappy in ParadiseWell, I can't disagree that Ruby on Rails has brought back the fun to web application development. It is probably because of the fact that I can produce results quickly with very small quantities of my own code that I'm prepared to spend more time improving the code itself. Using other frameworks, I was too exhausted simply getting the thing to work, to do anything more.
Also, I am extremely happy with the framework itself. A lot of people have put many man years of effort into creating and perfecting it. All I'm concerned with are the generators, or more precisely, the generator templates. Since they are there, in glorious source code, I see no reason not to modify them – at least for this particular application.
The ModelsWhat I didn't like about the User and Picture models was adding instance variables for what are, essentially, form fields – the password_confirmation and the uploaded picture file. The idea was to create sub classes for the 'form' versions of the model.
The ControllersThe generated controllers use the exception throwing find method to retrieve the object with a specified identifier. I thought I'd need to modify the template, but actually Rails provides several methods to look after exceptions – you've just got to know that they're there.
I do, however, think that the update and destroy methods needs some protection – at least they should check that the request was a post?, otherwise, in the case of destroy, all you have to do is type /users/destroy/1, and the user (and associated albums and pictures) are gone forever.
Maybe there should be a delete page, to confirm that you really do want to (permanently) remove all that work?
The ViewsThe generated views are clean and simple. Unfortunately, they're a little too simple to be easily manipulated by CSS rules. I don't see any reason for not using a table to format the new, edit and show pages. I also decided that I wanted a delete page, and add a delete? option to the edit page.
Reworking the ApplicationI froze the Rails application (which I do as habit), so the modifications have only been made to this single application, not to Rails itself, stored in the Ruby folder, because they'd be overwritten on the next gem update.
All of the templates, and their scripts can be found in the railties/lib folder, more precisely in vendor/rails/railties/lib/rails_generator/generators/components/.
The model script and templates that I modified are in, surprisingly, the model folder:
model/
model_generator.rb
templates/
model.rb
edit_model.rb
I modified the model_generator.rb to create a second model file, called edit_model.rb, which handles the edit form properties. I added comments in the model.rb file to remind myself where to look for the association and validation methods that will almost surely need to be added.
The major modifications, and general tweaking take place in the scaffold folder:
scaffold\
scaffold_generator.rb
templates\
style.css
view_index.html.erb
view_show.html.erb
view_new.html.erb
view_edit.html.erb
view_delete.html.erb
controller.rb
Basically, I made a one line change to the script scaffold_generator.rb to create an additional view_delete.html.erb template, and then added quite a lot of HTML code to the view templates themselves. That meant updating the style.css file too.
In the controller.rb template I added a set of verify method calls, and commented lines for filtering. I also added a delete method to handle delete page requests, and dummy rescue_action_locally and rescue_action_in_public methods, to remind myself that they're there, and should be used. I also added a generic filter_rescue_action method, as a dummy example of around_filter implementation.
The edit method also got a work over, to accept deletion code (so that I would have a choice, either a delete page, or a delete button in the edit page).
The ResultsGenerally, I am happy with the new views. Here are a few screenshots, after hand tuning the pages (mostly deleting unnecessary fields). The first is the home (index) page:
![]() Next is the show page for an album, including picture list (which I cut and pasted from the picture index page):
![]() Finally, the edit page, with edit or delete form:
![]() In the end I decided that I preferred having the delete option in the edit page – deleting something is an editing action. I simply couldn't think of a link text to the delete page that wouldn't frighten the user; “Confirm to delete” just didn't seem to cut it.
Minor breakagesUnfortunately, sub classing the model for the forms created some problems. Rails 2.0 adds extra features to the link_to and redirect_to methods where you only need specify the object (a @user for example), and Rails works out the rest from the class name. Change the class name and this breaks, so I had to do a little more tweaking than I'd anticipated.
In the views, for example, the original
<%= link_to 'Show', @user %> had to be converted to
<%= link_to 'Show', user_path(@user) %> since @user had changed from being a User class, to being an EditUser sub class of User. The same problem occurred in the form itself:
<% form_for(@user) do |f| %> became
<% form_for(:user, @user, :url => user_path(@user)) do |f| %> Yuk. Maybe sticking to Modules is the better policy.
The controller also had to endure similar modifications:
# POST /users
# POST /users.xml
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
session[:user_id] = @user.id
flash[:notice] = 'User was successfully created.'
format.html { redirect_to(@user) }
format.xml { render :xml => @user, :status => :created, :location => @user }
else
format.html { render :action => "new" }
format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
end
end
end
becomes:
# POST /users
# POST /users.xml
def create
@user = CreateUser.new(params[:user])
respond_to do |format|
if @user.save
session[:user_id] = @user.id
flash[:notice] = 'User was successfully created.'
format.html { redirect_to user_path(@user) }
format.xml { render :xml => @user, :status => :created, :location => @user }
else
format.html { render :action => 'new' }
format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
end
end
end
Not overly taxing modifications, but modifications nonetheless.
The WebAlbum application, and the modified templates used can be found in the RubyOnRailsWebAlbum.zip archived file. Be warned, though – this is a 4 MB file. The password for both users (jhl and lug) is villafranca. The source code is licensed identically to Ruby on Rails, using the MIT license.
ContactsSyger can be contacted for consultancy work on any of the topics mentioned in this article, by sending an email to info@syger.it.
|
Tag cloud: |