Archive for March, 2010

ActiveHelper 0.1.0 released

Tuesday, March 30th, 2010

Finally – helpers with proper encapsulation, delegation, interfaces and inheritance!

When I was prototyping a new JavaScript generator library using Rails’ helpers I came to a conclusion: Helpers suck.

Typically helpers in ruby frameworks are implemented as simple modules. However, despite the word simple, they suffer from two problems:

  • Dependency helper modules assume there are other helpers mixed into the target and blindly use foreign methods
  • Dependency helper modules rely on instance variables from the target they were mixed into.

ActiveHelper - An example

ActiveHelper puts helpers back to where they belong: classes.

Here’s how a typical MVC helper would look like with ActiveHelper. And, hey, if this is too brief, go and check out the README.

class View
  include ActiveHelper
 
  def https_request?; false; end
end

We have an exemplary View class that knows if an HTTP request is secure or not.

use

The include pendant for helpers and target instances is use.

> view.use FormHelper

The instance can use a helper to gain he-man’s form building capabilities.

class FormHelper < TagHelper
  provides :form_tag
  uses UrlHelper
 
  def form_tag(destination)
    destination = url_for(destination)  # in UrlHelper.
    tag(:form, "action=#{destination}") # in TagHelper.
  end
end

provides

The FormHelper exposes its interface as it provides a method #form_tag that itself uses two foreign methods #tag and #url_for.

The #tag method is simply inherited from the TagHelper, which provides :tag again. See the inheritance?

The latter, #url_for, is implemented in UrlHelper, so the form lib references that dependency when it uses the required helper.

needs

Let’s look into that url thing helper.

class UrlHelper < ActiveHelper::Base
  provides  :url_for
  needs     :https_request?
 
  def url_for(url)
    protocol = https_request? ? 'https' : 'http'
    "#{protocol}://#{url}"
  end
end

You already got it, don’t you?

The UrlHelper relies on a mysterious method #https_request?. There is no magical inclusion somewhere. As soon as it needs a method an accessor will be created delegated all calls to the View instance, which was the target.

Handling dependencies

So it’s the importing instance that has to handle methods declared with needs.

If the view wouldn’t expose the required method, it would be like

> view.form_tag('apotomo.de')
# => 11:in `url_for': undefined method `https_request?' for #<View:0xb749d4fc> (NoMethodError)

which is a clear, debugable issue.

Come on!

The approach found with ActiveHelper is completely generic, not bound to a specific framework like Rails, Merb or Sinatra. It may (and should!) be used in order to make helpers cleaner, use OOP features and make them easier to debug.

What’s your impression, what’s your problems and experiences with helpers? Don’t be shy, tell us!

Curious about the source? Check out my repository at the github, trans.

Cheers!

What about pagination? (Part 2)

Saturday, March 27th, 2010

The list we wrote yesterday was just a basic example (we finished with tag 0.3). Today we’re gonna paginate the list using the plugin will_paginate.
That serves a couple of purposes:

  • limiting the amount of items will help keeping the UI clean
  • using will_paginate proofs that helpers in widgets are just like helpers in controllers
  • switching to AJAX pagination will touch Apotomo’s simple event handling

1Limiting the item list means limiting the #find operation in our list widget.
app/cells/item_list.rb

class ItemList < Apotomo::StatefulWidget
  def display
    @items = Todo.paginate :page => param(:page), :per_page => 10, :order => 'created_at DESC'
 
    render
  end
end

That’s dead simple, we just exchanged #find with #paginate. Accessing request parameters can happen with params[], however, in widgets it’s a good practice to stick to #param.
The later prevents you from accessing parameters not bound to your widget.

2 Obviously we need to fix our view as well, as pagination only makes sense when we got buttons to switch pages.
app/cells/item_list/display.html.haml

%h3 Things
%p
  = page_entries_info @items
 
%ul
  - @items.each do |item|
    %li
      = item.text
 
= will_paginate @items

simple_paging
When viewing our page, we got a basic paging list, clicking a page button issues a new request.

3That works (tag 0.4), but it’s not the concept behind widgets. Widgets usually want to update via AJAX to save load time and to assure proper encapsulation.

Why should we reload the whole page for updating a single list? That’s overhead!

Keeping that in our collective mind we should add ajaxed buttons.

4Unfortunately will_paginate doesn’t provide a simple way to change the rendering of links (what about some block that’d define the link markup, mislav?) so we’re goin’ that way by foot.

app/cells/item_list/display.html.haml

1
2
3
4
5
6
7
8
9
10
11
%h3 Things
%p
  = page_entries_info @items
 
%ul
  - @items.each do |item|
    %li
      = item.text
 
- (1..@items.total_pages).each do |page|
  = link_to_event "|#{page}| ", :paginate, :page => page

We still use the handy #page_entries_info in line 3. To generate the page list we iterate through all available pages (line 10) calling a yet fameless method #link_to_event.

ajax_paging
5 The small helper method creates linked page numbers (|1| |2|). When clicking, nothing happens.

Well, you just fired an event! Looking at firebug’s XHTTP tracking, a :paginate event is triggered in the 'dashboard_list'. That’s our baby!

6Alright, so let’s handle this event. In Apotomo, triggered events can be observed, maybe we should try that.

1
2
3
4
5
6
7
8
9
class ItemList < Apotomo::StatefulWidget
  def display
    respond_to_event :paginate, :with => :display
 
    @items = Todo.paginate :page => param(:page), :per_page => 10, :order => 'created_at DESC'
 
    render
  end
end

Another apotomo’ed method, #respond_to_event, instructs our list to run the #display state again when it encounters the :paginate event (line 3).

After clicking a page link the updated list appears instantaneously. At the right place. Suuuperfast. Via AJAX. That means:

  • the :paginate event is triggered
  • it’s catched by our list widget using #respond_to_event
  • the list invokes the #display method again
  • the new content replaces the old content, automatically

Cool.

But there’s more.

In the next lessons we’ll polish our list view and add another widget for posting new items. Hope to see you, guys! COMMENT.

Go to: Unobstrusive JavaScript

Meet the StatefulWidget! (Part 1)

Saturday, March 27th, 2010

Hey, great, you decided to dive into Apotomo. Most people didn’t regret that, so far. For Will, Apotomo is “what was missing in my two years of study of Ruby on Rails”, for Andy “it’s like a breath of fresh air for rails”, and for Markus, it’s just “sexy”.

A very simple item list.
In this tutorial we’re going to model and implement a small todo application, namely dumdidoo, which saves and displays things you have to do.

1 It’s on github, so go and get it. Be sure to change to the 0.1 tag, so you’re at the very beginning of our exciting way.

$ git clone git://github.com/apotonick/dumdidoo.git
$ cd dumdidoo/
$ git submodule init
$ git submodule update
 
$ script/server

When browsing to http://localhost:3000/dashboard you see the raw view of the #index action in the DashboardController.

2Luckily, I already provide you with some Todo model and random items in the database. What about some list widget to show the items?

$ script/generate widget item_list display --haml
      create  app/cells/
      create  app/cells/item_list
      create  test/widgets
      create  app/cells/item_list.rb
      create  app/cells/item_list/display.html.haml
      create  test/widgets/item_list_test.rb

Just telling the widget generator to create things for me. It spits out the widget class in app/cells/item_list.rb and a bare view for the display state.

In Apotomo a widget is like a controller in Rails, and a state is similar to an action. The standard state of a widget is usually #display, that’s somehow matching to the index action in a controller.

So if you look into the widget class and view files you’ll see they look like good old controllers!

3To plug the widget into a page we have to work in the controller.

1
2
3
4
5
6
7
8
9
class DashboardController < ApplicationController
  include Apotomo::ControllerMethods
 
  def index
    use_widgets do |root|
      root << widget(:item_list, 'dashboard_list')
    end
  end
end

In Apotomo, widgets are organized in a tree. The #use_widgets method yields this ominous root node, and we attach a widget of type item_list to it, identified by ‘dashboard_list‘.

We need the id to render that widget.

app/views/dashboard/index.html.erb

<h2>Dashboard</h2>
 
<%= render_widget 'dashboard_list' %>

Ok, so we can call #render_widget in controller views to render widgets that we defined earlier with #use_widgets. Widgets, widgets, widgets…

blank_cell

When viewing the page, the widget’s default view appears within the controller’s view. That looks trivial, but, hey, you implemented your first widget! Congratulations!

4Now it’s time to extend this item_list widget and add functionality to list the items.

1
2
3
4
5
6
class ItemList < Apotomo::StatefulWidget
  def display
    @items = Todo.find :all
    render
  end
end

app/cells/item_list.rb

This will collect all the Todo items and push ‘em to an instance variable of our widget.

The render call without any arguments just looks for the corresponding view in app/cells/item_list/ (which is named after the state). In our case, it will find app/cells/item_list/display.html.haml.

Note that you could also have erb views, or builder, or whatever you prefer.

%h3 Things
 
%ul
  - @items.each do |item|
    %li
      = item.text

app/cells/item_list/display.html.haml

Widget views can access instance variables from its widget instance, just as you know that from ordinary controllers.

simple_listWhen browsing back to the page, we see the list of all Todo items!
Wow! You just learned how to implement encapsulated, reuseable components, and we’re at tag 0.3, yet.

5I was drunk yesterday. Today, I’m tired. I will stop here. Did it take you 12 minutes? No? Do you have questions already? Feel free to use the comments below.

Well, tomorrow we’re gonna extend the list, so it is pageable. We’re gonna use will_paginate for that and on top of that we’ll get AJAX paging. Exciting!

Go to: AJAX Paging

Your 12 Minutes of Apotomo - new weekly tutorial series launched!

Saturday, March 27th, 2010

I’m happy to announce a new tutorial series “Your 12 Minutes of Apotomo” which will appear at least once per week, stealing up to 12 minutes of your worthy time per lesson in exchange for learning Apotomo.

dumdidoo

Apotomo is stateful widgets for Ruby and Rails that help you keep your code clean and enrich your user interfaces with components.

And what do we do?

We’re gonna develop a small Todo app dumdidoo with Rails that utilizes a bunch of nifty Web 2.0 features, including

  • dashboards with slots for widgets
  • tab panel and more popular elements for a user-friendly GUI
  • drag&drop everywhere
  • AJAX pagination, form processing and file uploads

Sounds cool, what else?

This is not a JavaScript tutorial, it is all Ruby! From a software developer’s point-of-view you’re gonna learn about

  • UI design with widgets
  • component-oriented architecture
  • event triggering in the browser and in your Ruby code
  • event mapping from JS to Ruby
  • statefulness and persistence vs. traditional Rails controllers
  • unit- and functional tests for components
  • YUI controls integration in your Rails app with Apotomo’s YUI widgets

Can we go?

The first lesson is right here.

And, please…

Open your mouth and post questions so we can discuss obscure things in the next lection. Also, don’t be shy and post “feature requests” (what you’d like the app to do) cause I need to know what you guys want.

We can implement proposed features in one of the following lessons.

Looking forward to the trip!

Go to: Basic widgets

Onfire brings bubbling events to your Ruby objects

Friday, March 19th, 2010

In the current refactoring of Apotomo I finally extracted the bubbling event library into a separate ruby gem Onfire.

Bubbling events is, in contrast to Ruby’s own Observable module, focused on observing events triggered by business objects, not watching the objects themselves.

In addition, a triggered event will bubble up the tree branch and subsequently inform all ancestors- you get automatic organic event filtering.

Complete instructions are on the github page.

Let’s see how it works.

> require 'rubygems'
> require 'onfire'
> class Object
>   include Onfire
>   attr_accessor :parent
> end

Bubbling events only make sense in a tree structure. That’s why Onfire has one requirement to the class it’s mixed into- #parent.

ruby = Object.new
 
ruby.on :syntaxError do |event| puts "ruby: omg, a syntax error in #{event.source}" end
ruby.fire :syntaxError
# => ruby: omg, a syntax error in #<Object:0xb75a087c>

That was simple, Observable can do this, too.

Appending a method

Now let’s add a method object to ruby.

method = Object.new
method.parent = ruby
 
method.on :syntaxError do |event| puts "method: a syntax error in ME?" end
method.fire :syntaxError
#=> method: a syntax error in ME?
#=> ruby: omg, a syntax error in #<Object:0xb756dd00>

The event bubbles. What about some variable in the method?

variable = Object.new
variable.parent = method
 
variable.on :syntaxError do |event| puts "variable: I am the problem." end
variable.fire :syntaxError
#=> variable: I am the problem.
#=> method: a syntax error in ME?
#=> ruby: omg, a syntax error in #<Object:0xb756dd00>

Extending the tree model

Maybe there’s another method attached to ruby.

method2 = Object.new
method2.parent = ruby
 
method2.on :syntaxError do |event| puts "method2: Whoops, something here is wrong." end

Now if variable fires, method2 shouldn’t be informed. Remember, the variable is in method.

variable.fire :syntaxError
#=> variable: I am the problem.
#=> method: a syntax error in ME?
#=> ruby: omg, a syntax error in #<Object:0xb756dd00>

Works. That’s organic event filtering resulting from ascending event propagation.
The bubbling event from variable never hits method2 on its way up.

Stopping the event

What if method wants to intercept syntax errors in its scope, so ruby won’t get informed any further about errors in method?

method.on :syntaxError do |event| 
  puts "method: that's private things"
  event.stop!
end
 
variable.fire :syntaxError
#=> variable: I am the problem.
#=> method: a syntax error in ME?
#=> method: that's private things

The event stops in method.

And what if method2 contains errors?

method2.fire :syntaxError
#=> method2: Whoops, something here is wrong.
#=> ruby: omg, a syntax error in #<Object:0xb75348d4>

It still bubbles up to root. Yeah, makes sense, it’s a different tree branch.

More!

I told you, more examples, source filtering, bubbling, babbling, intercepting on the github. Have fun and let me know how it works for you!