September 17, 2008

Probably one of the hardest adjustments to make when transitioning from Desktop forms development to browser-based is the endless number of code and template files that must be created and maintained just to have one working “form” (that you will now be calling a “page”).

With a traditional desktop form, it usually isn’t hard to get your arms around all of the “players” involved in making your form work. You may have many “layers/tiers”, but most of the pieces are probably written in the same language using the same IDE. This is not the case when designing web pages/forms where the content for each page is spread across several files (at a minimum) each of which are probably using very different development languages and/or markup styles.

Why have all of these “pieces” of code and/or markup all over the place?

DRY (Don’t Repeat Yourself) DRY is one tenet of Rails development. It basically says “if you are copying/pasting the same code/markup into multiple files, that code/markup should be put into it’s own file which should just be pulled into the pages that need it at run-time.” Yes, that is my own paraphrase 🙂

WWW = Best Of BreedWeb development has accelerated the pace at which tools and technologies are evolving. We web developers love to complain about all the “disconnectedness” that exists in web-based apps, but we would really scream if some new technology came out and we had to wait a year for some company to boil out the impurities and then bloat it up so it could be “assimilated” before we could work with it (wait, I know that company…). HTML, CSS, and JavaScript are poster-child technologies for “survival of the fittest” or should I say “survival of the most flexible but yet most simple”… nah, doesn’t have the same ring to it.

So, with just these three demands placed on us as a pre-requisite for developing a web form, it’s no wonder that we end up with so many disparate technologies and pieces all needing to converge without errors inside multiple versions of non-standard browser implementations across multiple operating systems. Oh man, my stomach just knotted up right there… okay, Ruby and Rails to the rescue!

Anatomy Of A View

The following “pieces” are used to produce a single web page/form:

HTML (ERB)

The main part of a web page or “form”. It resides in \app\views\modelname\myview.html.erb. Many people consider this the “view”, but it is only one component of the view. This one file actually contains many types of coding/markup/templating.

Your cascading stylesheet(s) which control most of the presentation properties of your page/form. You will almost always have at least one of these for each application. It is very likely that you will have several.

CSS stylesheets are stored in \public\stylesheets\.

Which stylesheet to use is usually established in either an application-level or a controller-level Layout file like this: <%= stylesheet_link_tag ‘mystyle’ %>

JavaScript

Your JavaScript classes/functions and 3rd party tools like Scriptaculous, Prototype, and JQuery. Your application will usually use at least 3 JSP libraries. Large AJAX-driven client applications can have…lots of them!

JavaScript code files are stored in \public\javascripts\.

Usually, the Layout file will include: <%= javascript_include_tag :defaults, :cache => true %> which will include the 5 most commonly used javascript libraries (including Scriptaculous and Prototype).

You can also specify <%= javascript_include_tag :all, :cache => true %> which will automatically include EVERY javascript file found in \public\javascripts\

You can also specify <%= javascript_include_tag ‘prototype’, ‘effects’, ‘controls’, :cache => true %> to control which libraries load or the order in which they are loaded.

Helper(s)

Helpers blur the line between a Controller and a View. As Dave Thomas so brilliantly put it, “A helper is simply a module containing methods that assist a view. Helper methods are output-centric. They exist to generate HTML (or XML, or JavaScript)-a helper extends the behavior of a template.”

Helpers are stored in \app\controllers\helpers\

Controller-specific Helpers are named after their Controller with “_helper.rb” appended to the end.

The Application-wide Helper is \app\controllers\helpers\application_helper.rb

Layout(s)

A layout is kind of like an HTML/ERB fragment or snippet that gets pulled into your page template at run-time and is usually used to show data/text on the page this is generic across all views/pages for the Controller (like headers, footers, borders, etc.).

All layouts are stored in \app\views\layouts\ (defined by the constant TEMPLATE_ROOT)

Controller-specific layouts are named after their Controller.

The application-wide Layout named “application.html.erb”

The application-wide layout can be specified in \app\controllers\application.rb

Each Controller can override the application-level layout by setting the “layout” property or by passing :layout => ‘layouts/mylayout’ directly in the render( ) method call.

You can suppress the use of any Layout by including :layout => false in the render( ) method call.

Partial

Partials are very much like Controller-level Layouts because they are HTML/ERB fragments that get pulled into your page and rendered at run-time. The big difference is that Partials are typically used to display repetitive formatted information (like a grid with rows of records) using a code block (DO…END block).

This will render the partial _clientlist and pass it the local variables (from the Controller) and the set the variable “label_text” to the value "Update"

Rails 2.0 introduced the ability for a Partial to have it’s own Layout. Yes, it does seem a bit like nesting, but it is nice to have! Now, we can do something like this in our HTML/ERB file: <%= render :partial => "header", :Layout => ‘boxed’ :locals => { :post => @post} %> which will pull in the Layout _boxed.html.erb, which will then pull in the Partial _header.html.erb.

Partials are usually used on a “per View basis” and are stored in \app\views\myview\

Partials are named beginning with an underscore (i.e. _mypartial.html.erb)

Partial Layouts are stored in the same folder as the Partial and also begin with an underscore.

You can re-use a Partial Layout across your application if you store it in \app\views\application\

Then, when calling the partial, just use :layout => ‘layouts\mylayout’

RJS

RJS templates also blur the line between the Controller and the View. They have access to all of the Controller objects/variables, but they also have an object reference to the current HTML “page” that is in the browser. RJS templates allow you to infuse JavaScript into your views that is written using Rails “helper methods” (instead of actual JavaScript). Separate RJS template files are not required (you can accomplish most of the same things with “render updates” directly in your Controller code).

RSJ template files are stored in \app\views\myview

RJS templates are named for the Controller “Action” from which they are called with a “js.rjs” extension.

RJS templates are not actually “called”, if one exists, it is simply applied when the view is rendered.

Make sure you don’t try to name an RJS template the same thing as the View, otherwise the View gets rendered, not the RJS.

So…

I just showed you how you could easily have 7 or more separate files using 5 or more different technologies included in the 1 page you are trying to display to the user. Hopefully, knowing is half the battle and at least the reasons “why” make a little more sense to you now. I also gave you a fairly concise list of the places where the creation/display of a Ruby On Rails “View” can go wrong. Using Ruby On Rails can sometimes seem like magic, and that is part of the fun. But, you at least need to know that there “is” someone behind the curtain and try to get as familiar as you can with the plumbing because one day it will back up!

How To Debug

Debugging an application with hundreds of files and so many combined technologies is no small feat. The first step is to remember that all of these “pieces” eventually get smashed back together into the HTML displayed in the browser! So, you can view the source of the page in the browser (Using the IE Developer Toolbar in Internet Explorer, or even better, using the Firebug plugin for FireFox).

Use a full-blown IDE with a built-in debugger (like Aptana with RadRails, Steel Sapphire, Komodo, etc.)

Use the Logs! Look at your log files, and don’t forget that you can pepper any problem code with manual log entries.

Use the IRB! The interactive Ruby console will allow you to spy on your objects and variables as well as manipulate them in real-time. Yes, it’s command-line Alice.

March 11, 2008

Variables in Ruby/Rails are of your fairly standard variety (local, instance, public). There is another type called “class” or “class instance” variables that get way too much attention for the amount they are used (or not used) in most apps. If you are learning Ruby/Rails, just ignore Class Variables for now and don’t use them.

Controllers and Views have a special arrangement though, since both of them are part of ActionPack. This means they actually share a codebase. (see http://ap.rubyonrails.com/ for a thorough a picture and an explanation)

…snippet… “Action Pack splits the response to a web request into a controller part (performing the logic) and a view part (rendering a template). This two-step approach is known as an action, which will normally create, read, update, or delete (CRUD for short) some sort of model part (often backed by a database) before choosing either to render a template or redirecting to another action. Action Pack implements these actions as public methods on Action Controllers and uses Action Views to implement the template rendering. Some of the features, are tied to ActiveRecord, but that doesn’t mean that Action Pack depends on Active Record. Action Pack is an independent package that can be used with any sort of backend.”

What this means for you, is that instance variables defined in a Controller are visible to any View called by that controller.

LocalVariable

current_time = Time.now

If defined in a Controller, it can NOT be seen from “any” View called by the Controller.

InstanceVariable

@current_time = Time.now

Can be seen only from “this” instance of this class

If defined in a Controller, it can be seen from “any” View called by the Controller.

Class(instance)Variable

@@current_time = Time.now

Can be seen and changed from “any” instance of this class (one variable shared across all instances)

If defined in a Controller, it can be seen from “any” View called by the Controller.

Even though your Controller Instance Variables will be visible to your View, your Controller Methods will not. You can get around this by placing methods that need visibility to the View in your Controller Helper (app\helpers\orders_helper.rb based on our example above).

– You have fields in your table that do not allow NULL. You will need to supply a value for them before you can save. *scaffold handles all of this for you.

– Internet Explorer cannot display the webpage

You do not have Apache/IIS started.

You do not have MySQL started.

You do not have the Ruby server started (See “Start the Server” above).
Remember, your “view” webpage is trying to execute ruby scripts that reside back on the server. Without a server component running, it cannot do anything.

You did not enter the address correctly in the browser (mispelled the view name).