Monday, March 31, 2008

Fitting Ext JS into the Rails architecture

When you start building your first Ext JS page into your Rails application, you certainly will wonder where to put the Javascript code.
Instead of just creating a javascript file such as posts_show.js in your public/javascript directory, here is a more elegant way for adding Ext JS pages to your Rails (2.0.2!) project:

# app/controllers/post_controller.rb

def show
@post = Post.find params[:id]

respond_to do |format|
format.html { render :layout => "extjs" } # *
format.js
end
end

# *) special extjs layout which includes the required extjs files,
# in case you have a different default layout for non-Ext JS pages


# app/posts/show.html.erb

<%= javascript_include_tag formatted_post_path(@post, :js) %>

# app/posts/show.js.erb

Ext.onReady(function(){
// your ext js javascript code here
// because this file is rendered via the erb renderer,
// you can add ruby code such as:
alert('<%= @post.title %>');
});

Thursday, March 27, 2008

Inspecting your Ext.onReady variables

In the Ext JS examples included in the Ext JS package, you'll find usually this code:

Ext.onReady(function(){
..
var store = new Ext.data.SimpleStore({
..
});

var grid = new Ext.grid.GridPanel({
store: store,
..
});
});


Notice the var keyword in front of the declared variables! The var keyword is defining the variables as local variables. They are only existing in the scope of the anonymous function which is passed to the Ext.onReady method.
But what if we'd like to inspect the values of our local variables in firebug? We could set a breakpoint inside our anonymous function which will allow us to inspect these local variables. But it's a little annoying to do that everytime we're working on an Ext page.

Well, we just could remove the var keyword or use this.store. But that would clutter up our global scope which isn't that nice.

Here is a better solution I came up with today:

Ext.screen = {}

Ext.onReady(function(){
var s = Ext.screen;
..
s.store = new Ext.data.SimpleStore({
..
});

s.grid = new Ext.grid.GridPanel({
store: s.store,
..
});
});


With that solution all our local variables can be referenced by Ext.screen.variable in our firebug console, while keeping our global scope clean by using the Ext.screen namespace.

ext-all.js or ext-all-debug.js

To ease the debugging process, the Ext JS package includes the uncompressed javascript files of their library as well.

Here's a small Rails helper to add the Ext JS library files based on your Rails environment:

# app/helpers/application_helper.rb
module ApplicationHelper

... # your other helpers here

def javascript_include_extjs
if RAILS_ENV == "production"
javascript_include_tag "ext/adapter/ext/ext-base.js", "ext/ext-all.js"
else
javascript_include_tag "ext/source/core/Ext.js", "ext/source/adapter/ext-base.js", "ext/ext-all-debug.js"
end
end

end



In your view layout header you just need to call:


<%= javascript_include_extjs %>


Important: Don't forget the ext js css files!

P.S.
You can find some more hints on debugging Ext JS here.

Sunday, March 23, 2008

Sending forms the "old way" with Ext JS

The normal non-AJAX life-cycle of sending a form in Rails is the following:

  1. The user submits the form
  2. The browser is going to the form's action url
  3. The Rails action calls some model methods and sends a redirect to the users browser to a overview page or the created record for example
Here are some code snippets to solve this life-cycle with Ext JS and Rails:

// ext js form

var submit_button = new Ext.Button({
text: "Submit",
handler: function () {
form = this.ownerCt.getForm();
form_as_dom = form.getEl().dom;
form_as_dom.action = form.url;
form_as_dom.submit();
}
})

new Ext.form.FormPanel({
url: "<%= confirm_order_path(@order)%>",
standardSubmit: true, // doesn't do anything in ext js version 2.0.2
items: submit_button
})

# rails controller action

def confirm
order = Order.find params[:id]
order.confirm!
order.save # no error handling in this example

redirect_to order_path(order)
end


The special thing here is, that Ext JS doesn't really support the old-way of sending form data to the browser. But it's actually on their roadmap for the 2.1 release in this spring, which should be out very soon. The above code shows the current "work around" by using the actually DOM object of the form.

For completion and comparison, here the code for doing a form submit via AJAX.

// ext js form

var submit_button = new Ext.Button({
text: "Confirm",
handler: function () {
form = this.ownerCt.getForm()
form.submit({
success: function () {
this.setText("Unconfirm");
form.url = "<%= unconfirm_order_path(@order) %>";
},
scope: this
});
}
})

new Ext.form.FormPanel({
url: "<%= confirm_order_path(@order)%>",
standardSubmit: false, // false by default,
// but doesn't do anything in ext js version 2.0.2
items: submit_button
})

# rails controller action

def confirm
order = Order.find params[:id]
order.confirm!
order.save # no error handling in this example

render :text => "{ success: true }" # ext js converts
# responses to json by default, that means no need
# to send an explicit json header
end

Saturday, March 22, 2008

Discovering Ext JS with Rails

Before I discovered the Ext JS - Javascript Library in November 2007, I was working with Ruby on Rails for almost a year. (I know, pretty late since Rails came already out in 2004, but I was stuck with my PHP Projects.)

From then on, Rails was really helping me to get my models and controllers in order. But what about the view layer? Yes, Rails was helping me here, too. But not as much as on the model and controller level. I like partials, helpers and rjs, but building a nice graphical interface was still a lot of work.

When building graphical interfaces the first thing you need to have is an idea what the user is supposed to do on the interface.

Second, you need to think about the layout and what elements you want to put on the interface (separated in pages or states). In this step, you as an interface developer have so much freedom that you can end up weeks and months moving around elements and pixels on your interface seeking for the best usability and look. Ext JS doesn't really limit your freedom, but it gives you very very helpful guidelines for building nice interfaces, since it has ready-to-use widgets such as grids, panels, buttons, menus and toolbars which can be configured via options to your need. Ext JS is for the client-side of web applications as Ruby on Rails is for the server-side of web applications.

Third, you have to design the interface elements on yourself or by a designer. Ext JS includes nice GUI elements or so-called widgets out-of-the-box. Some may argue the Ext JS theme is very "Windows Vista"-like, but it's gives you at least a beautiful interface right at the beginning which can be customized by you without limits.

Forth, you need to build the interface. Building the interface can be tricky, especially today when everybody is expecting some fancy AJAX, which can be very useful in a lot of cases. Now the fight with Javascript, CSS, ERB, controller actions and cross-browser compatibility is starting. The Rails built-in javascript libraries Prototype and script.aculo.us or additional template engines like Haml or Markaby can help you with this step, but it's still not less complicated.
With Ext JS, you have everything in one library which has a very clean API and documentation. You actually have to use actually HTML or Haml very few times, since you can build the whole interface by Ext JS widgets and layouts which are configured by options in the JSON-Format.

Therefore, the best solution and more and less silver bullet for building web-based user interfaces is for me Ext JS.

I'm starting this blog to document some hints and tipps on using Ext JS together with Ruby on Rails. But this blog is not supposed to be an one-way street. Through this blog I hope to meet other Rails developers that use Ext JS and have their own solutions and tipps. I welcome everybody to use the comments feature or send me an email to s dot hiller at caprireleases dot com.