Posts filed under 'Ext JS'

Howto: Associations with ext_scaffold (aka ExtJS with Ruby on Rails)

Jonathan Barket kindly compiled a nice howto on leveraging belongs_to associations in ext_scaffold generated user interfaces.

Check it out!

Update: The above link points to a local copy of Jonathan’s article that was pulled from the Google Cache after he restructured his blog sadly dropping the original content.

Related Posts

Add comment February 17th, 2009

Announcing: Ext Scaffold Reloaded Plugin for Ruby on Rails

Ext Scaffold just got “Reloaded” for Christmas. Never heard of Ext Scaffold? Ok, so first things first:

The Ext Scaffold Generator Plugin is a drop-in replacement for Rails’ standard Scaffold Generator. Accepting the very same options, it will generate views using data grid and form components from the Ext JS Javascript GUI framework as well as a controller acting as an Ext-compatible JSON web service. The generated code can be used as a starting point for further implementation and outlines solutions on how to integrate the Ext JS library with Rails as a backend.

When Ext Scaffold was first released earlier this year, it was a rather experimental shot at Ext/Rails integration. It still received a lot of great feedback, and more importantly it helped me gather things I would do different next time.

Ext Scaffold Reloaded is the fruit of all lessons learned since the first release, if you will. So without further ado, here are the top enhancements:

  1. One-page user interface: The Grid and the form are integrated into one single page. As no page reload is necessary when switching between grid and form, the interfaces is much more responsive.
  2. No more magic: The formerly introduced view helpers are gone. While they made the view code look very simple and elegant, they more so obfuscated what was actually going on.
  3. Easy refinement: All Javascript code is now generated explicitly and thus can be easily tweaked and refined to one’s needs.

Ext Scaffold also found its new home over at github. So give it a spin and let me know what needs to be radically different in the Revolutions release ;-) .

Recommend Martin Rehfeld on Working With RailsIf you like this plugin, please consider recommending me on Working with Rails. Thank you!

Related Posts

4 comments December 24th, 2008

Advanced Ext JS Form Controls with Ruby on Rails: ComboBox

The Ext Scaffold Generator Plugin for Ruby on Rails provides a quick start for single-model forms. When proceeding from the generated code to an actual application, one question keeps popping up in no time:

“How can I have a ComboBox in my form populated with choices from some other model to assign a association?”

Say, you have a Post model for blog posts and a Category model, similiar to the one we used in the Treeview example. Each Post belongs to a Category:

class Post < ActiveRecord::Base
  belongs_to :category
  # has attributes: id, title, body, category_id
end
class Category < ActiveRecord::Base
  # has attributes: id, name
end

If we were using just Rails without Ext JS, we would probably have the select form helper build a HTML select field ending up with this sort of code in our view:

<%= select :post, :category_id,
       Category.find(:all).collect {|c| [ c.name, c.id ] },
       { :include_blank => true } %>

Guess what? You can use the exact same code with Ext JS. One of the handy features of Ext.form.ComboBox is the ability to transform an existing HTML select tag into one of Ext’s nice looking controls.

To turn above select field into a Ext.form.ComboBox we can use this form item configuration:

{ fieldLabel:    'Category',
  xtype:         'combo',
  triggerAction: 'all',
  typeAhead:      true,
  forceSelection: true,
  transform:     'post_category_id',
  lazyRender:     true
}

A complete _form_items.html.erb partial (as used with the Ext Scaffold Generator) would then look like this:

<%= select :post, :category_id,
       Category.find(:all).collect {|c| [ c.name, c.id ] },
       { :include_blank => true } %>
<% javascript_tag do -%>
  var <%= "#{form_items}" %> = [
    <%= ext_field(:field_label => 'Title', :name => 'post[title]', :xtype => :text_field) %>,
    <%= ext_field(:field_label => 'Body',  :name => 'post[body]',  :xtype => :text_area) %>,
    { fieldLabel:    'Category',
      xtype:         'combo',
      triggerAction: 'all',
      typeAhead:      true,
      forceSelection: true,
      transform:     'post_category_id',
      lazyRender:     true
    }
  ];
<% end -%>

Recommend Martin Rehfeld on Working With RailsIf this mini-tutorial was useful to you, please consider recommending me on Working with Rails. Thank you!

Related Posts

6 comments February 2nd, 2008

Howto use the Ext JS Treeview (Ext.tree) with Ruby on Rails

ExtJS Tree Sample ScrenshotIn this little tutorial I am going to show you, how to connect a Ext.tree component (from the remarkable Ext JS Javascript framework) to a Ruby on Rails backend.

For starters, we need to download and extract the Ext framework to public/ext in our Rails project folder. We are going to use Rails 2.1.x for this Tutorial. That’s not a particular requirement - but you would have to adapt certain Rails 2 concepts should you be using an older version.

To model a tree in Rails, we are going to use the acts_as_nested_set plugin - install it using script/plugin install acts_as_nested_set now.

To demonstrate the Ext.tree I will be using a Category model, having a root category with recursive sub-categories. We can use the Rails resource generator to initialize all neccessary files for us:

script/generate resource Category parent_id:integer lft:integer rgt:integer text:string

As you can see, each of our categories is just carrying a text attribute to store its name and the required attributes for the nested set (parent_id, lft, rgt).

To use the Category model, we just have to add the acts_as_nested_set decorator to the Category class, so it looks like this:

class Category < ActiveRecord::Base
  # For Rails 2.1: override default of include_root_in_json
  # (the Ext.tree.TreeLoader cannot use the additional nesting)
  Category.include_root_in_json = false if Category.respond_to?(:include_root_in_json)

  acts_as_nested_set
end

We can now create some sample data using script/console (you did run rake db:migrate already, didn’t you? ;-) ):

r = Category.create(:text => 'Frameworks')
r.add_child(c1 = Category.create(:text => 'Ruby on Rails'))
c1.add_child(Category.create(:text => 'Model'))
c1.add_child(Category.create(:text => 'View'))
c1.add_child(Category.create(:text => 'Controller'))
r.add_child(c2 = Category.create(:text => 'Ext JS'))
c2.add_child(c21 = Category.create(:text => 'tree'))
c21.add_child(Category.create(:text => 'TreePanel'))
c21.add_child(Category.create(:text => 'AsyncTreeNode'))
c21.add_child(Category.create(:text => 'TreeLoader'))

On to our CategoriesController. We just need an index method that will initially deliver a (rather static) index.html.erb view. The same method can then be used to provide JSON data to be consumed by Ext.tree like this:

class CategoriesController < ApplicationController
  def index(id = params[:node])
    respond_to do |format|
      format.html # render static index.html.erb
      format.json { render :json => Category.find_children(id) }
    end
  end
end

We are giving the index method a node query parameter (assigned to a id variable) that Ext will later use to dynamically request sub-trees as they are extended in the UI.

Obviously we will have to add more code to our Category model as it currently does not respond to the find_children method. Let’s use the following code to provide it - when no id or zero is given, the root node(s) of the tree will be returned:

  # add to model/category.rb
  def self.root_nodes
    find(:all, :conditions => 'parent_id IS NULL')
  end

  def self.find_children(start_id = nil)
    start_id.to_i == 0 ? root_nodes : find(start_id).direct_children
  end

After starting script/server we can now fire up our browser and request http://localhost:3000/categories.json. Comparing the generated JSON with the format expected by Ext.tree.TreeLoader reveals that each element should supply a boolean attribute called leaf telling the tree if it can be further expanded or is a final leaf of the tree. To keep our controller skinny as we like it, we will add further methods to the Category model enabling its standard to_json method to also supply the required leaf attribute.

  # add to model/category.rb
  def leaf
    unknown? || children_count == 0
  end

  def to_json_with_leaf(options = {})
    self.to_json_without_leaf(options.merge(:methods => :leaf))
  end
  alias_method_chain :to_json, :leaf

Now that we have the complete backend code in place, we just need to put some Ext Javascript into categories/index.html.erb to try the tree live:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <title>Ext.tree with Ruby on Rails Example</title>
  <%= stylesheet_link_tag "../ext/resources/css/ext-all.css" %>
  <%= javascript_include_tag :defaults %>
  <%= javascript_include_tag "../ext/adapter/prototype/ext-prototype-adapter.js" %>
  <%= javascript_include_tag "../ext/ext-all.js" %>
</head>
<body>
  <div id="category-tree" style="padding:20px"></div>
  <% javascript_tag do -%>
    Ext.onReady(function(){
      // create initial root node
      root = new Ext.tree.AsyncTreeNode({
        text: 'Invisible Root',
        id:'0'
      });
      // create the tree
      new Ext.tree.TreePanel({
        loader: new Ext.tree.TreeLoader({
          url:'/categories',
          requestMethod:'GET',
          baseParams:{format:'json'}
        }),
        renderTo:'category-tree',
        root: root,
        rootVisible:false
      });
      // expand invisible root node to trigger load
      // of the first level of actual data
      root.expand();
    });
  <% end -%>
</body>
</html>

Now it is time to look at the final view (http://localhost:3000/categories). If you use Firebug or something similar you can track the AJAX requests made by Ext.tree to populate the tree dynamically when you expand nodes. Nice, huh?

Recommend Martin Rehfeld on Working With RailsIf you like this tutorial, please consider recommending me on Working with Rails. Thank you!

Related Posts

20 comments January 26th, 2008

Announcing: Ext Scaffold Generator Plugin for Rails

Ext Scaffold Generator Plugin GUI Screenshot.png

Update (12-2008): Ext Scaffold Reloaded has been released. While the version discussed in this post is still available, I strongly suggest looking into the latest version over at github/ext_scaffold. The Reloaded edition offers a richer UI, better performance and can be customized much easier — it is the fruit of all lessons learned since the first release, if you will. Read the announcement.

The Ext Scaffold Generator Plugin can be viewed as a drop-in replacement for Rails’ standard Resource Generator. Accepting the very same options, it will generate views using data grid and form components from the Ext JS Javascript GUI framework as well as a controller acting as an Ext-compatible JSON web service. The generated code can be used as a starting point for further implementation and outlines solutions on how to integrate the Ext JS library with Rails as a backend.

What it does not do

Ext JS is huge. It provides just about any component for developing Rich Internet Applications. The Ext Scaffold generator only uses a very limited subset of Ext JS. It includes some view helper methods to generate Javascript code, but these helpers are not really meant to be used in other contexts. IMHO it is better to code the Javascript in views by hand.

Any attempt of providing helpers for even a subset of the Ext functionality seemed like a dead-end approach to me. For further refinement of your application I suggest looking at the generated JS code and change it to suit your needs.

Features and Concepts

The way Ext JS works is to code all GUI components and interactions in Javascript. These components will then interact with a datastore backend via web service requests (either JSON or XML formatted).

The Ext Scaffold Generator Plugin provides a custom MIME type alias :ext_json to be able to handle requests from the Ext frontend separately. The generated controllers show how to do this.

To make data delivery to the Ext frontend easy, the plugin extends the Array and ActiveRecord::Base classes to provide a to_ext_json method. Here’s a simplified example of a potential index method in a PostsController:

# GET /posts
# GET /posts.ext_json
def index
  respond_to do |format|
    format.html     # index.html.erb (will fire ext_json request)
    format.ext_json { render :json => Post.find(:all).to_ext_json }
  end
end

to_ext_json will also format validation error messages attached to ActiveRecord::Base objects. This can be used to provide server-side validations additionally to Ext’s own client-side validation features in forms. Another simplified example using our fictitious Post resource:

# Model
class Post < ActiveRecord::Base
  validates_presence_of :title
end

# Controller
class PostsController < ApplicationController
# ...
# POST /posts
  def create
    @post = Post.new(params[:post])
    if @post.save
      flash[:notice] = 'Post was successfully created.'
      render(:update) {|page| page.redirect_to posts_url }
    else
      render :json => @post.to_ext_json(:success => false)
  end
end
# …
end

Installation

script/plugin install http://rug-b.rubyforge.org/svn/ext_scaffold

After the plugin has been installed, download the Ext Javascript framework from http://extjs.com/download and unzip it into #{RAILS_ROOT}/public/ext. The plugin was tested against version 2.0.1 of the Ext framework.

Usage Exmples (call without params for help)

./script/generate ext_scaffold post title:string body:text published:boolean
./script/generate ext_scaffold purchase order_id:integer amount:decimal

Recommend Martin Rehfeld on Working With RailsIf you like this plugin, please consider recommending me on Working with Rails. Thank you!

Related Posts

59 comments January 18th, 2008

Ext JS and Rails, how do they get along?

The Ext JS framework got a lot of attention lately as it offers very sophisticated GUI components for web application development. But how does Ext play along with Ruby on Rails, everybody’s favorite development framework?

There is not a lot of documentation around, though some people seem to be using the combo quite successfully (if you take job posts looking for Rails and Ext skills into account).

Googling reveals some Rails plugins aiming at Ext integration, but a closer look exposes them as mostly “vaporware”, abandoned experiments or as not being actively developed.

RailsExt.pngFor my talk on Ext at the Berlin Ruby Users Group, I decided to roll my own. The presentation focuses on Rails scaffolding as a good starting point for playing with Ext. The biggest integration task from a Rails point of view is providing the correct JSON data structures that Ext can process - a task that can be solved in a re-usable way. Passing data around between Rails controllers and views and the actual JavaScript code is another focal point. Download the complete set of slides here.

The presentation features a preview version of my Ext Scaffold Generator, soon to be announced as a official Rails plugin.

[Edit by martin.rehfeld]: The Ext Scaffold Generator has been officially released on 18th January 2008, check out the details.

Related Posts

12 comments January 8th, 2008

Ext JS already the 3rd most used Web Framework

Good to hear that Ext JS, the high level Javascript framework for rich GUI development is getting its well-deserved attention.

That also makes my time feel well spent on that talk about Ext JS with Rails on 10th January 2008, I’m currently preparing for the Berlin Ruby User Group (RUG-B).

Add comment December 17th, 2007


Posts by Category