Posts Tagged widget

Pragmatic Rails: Let’s do AJAX-backed Sidebar Widgets right, Jim!

Saturday, November 20th, 2010

Days ago I explained how to write a sidebar widget in Rails, using the view component framework Cells. This was fun.

The sidebar widget.

Clicking a tag leads to a page reload, where the Recent posts list displays items matching the tag, only. It worked great, however, each click needs a real HTTP request and a reload – let’s use AJAX to handle that.

Rails and AJAX? Apotomo!

Widgets+Rails usually means you’re better off using Apotomo , a new kid on the block. Apotomo is a web component framework for Rails, I will officially announce it in a separate post soon.

Let’s discuss how I converted the Recent posts cell into an interactive widget. If that’s too brief, there is a detailed in-depth tutorial here, just follow the links at Learn.

Check out the repository of this example app if you wanna play around.

Getting a cell interactive

We need the Apotomo gem, so I put it in the Gemfile.

gem 'rails', '3.0.1'
gem 'cells'
gem 'apotomo', "~>1.0"
# ... and so on

I would never forget to run bundle install, Freddi!

In order to make a cell a widget, I inherit from Apotomo::Widget.

class PostsWidget < Apotomo::Widget
  def display
    @tag    = param(:tag)
    @posts  = @tag ? Post.tagged_with(@tag) : Post.recent
    render
  end
 
  def tag_cloud
    @tags = Post.tag_counts_on(:tags)
    render
  end
end

Nothing really changed here, so far.

Note that deriving things from Widget doesn’t involve statefulness or anything – it’s just a nestable cell now, being aware to Apotomo’s events. Right, Ryan?

Widgets are cells

The assets layout slightly changed. Here’s how my app/cells directory now looks.

|-- posts_widget
|   |-- display.html.haml
|   `-- tag_cloud.html.haml
`-- posts_widget.rb

Some names changed, but we still got our views in a separate directory. Widgets also reside in app/cells, there’s no need to push another folder into Rails.

Rendering a widget

After these changes, rendering the widget turns out to be fucking simple, too.

%html
  %head
    %title "The Incredible Cells Blog"
 
  %body
    #sidebar
      = render_widget 'sidebar-posts'

I just call #render_widget where I used to call #render_cell in the application.html.haml layout.

The call referes to the widget id which is defined in the controller’s widget tree. Let’s see how that works, so we can render the component.

Messing up the widget tree

Usually, widget trees are declared on the controller class layer.

class PostsController < ApplicationController
  include Apotomo::Rails::ControllerMethods
 
  has_widgets do |root|
    root << widget(:posts_widget, 'sidebar-posts')
  end

Just include the necessary module and setup the tree using the has_widgets method. Notice how I refer to the widget class first, then I assign the id.

Wow- this already renders the Recent posts box! The #render_widget helper automatically invokes the #display state of the widget.

Triggering events

Clicking a tag still does a real request. As I want an AJAX call here, I change the tag_cloud.html.haml view a bit.

#tag-cloud
  - tag_cloud(@tags, %w(css1 css2 css3 css4)) do |tag, css_class|
    = link_to tag.name, "", :class => css_class, 
 
      'data-event-url' => url_for_event(:tagClicked, 
        :tag => tag.name)
 
:javascript
  $("#tag-cloud a").click(function(e) {
    $.ajax({url: $(this).attr("data-event-url")});
    return false;
  });

The first three lines didn’t change at all. However, two new steps involved here.

  • First we set an attribute in each clickable tag link. The #url_for_event computes some url needed to trigger the :tagClicked event in Rails.
  • Second a small jQuery script catches click events and fires an AJAX request to the “event url. This is that unobstrusive Javascript everybody’s talking about.

What we need to do now is catching the :tagClicked event in the ruby world and update the item list in the browser.

Luckily, Apotomo saves us from any routing and dispatching.

Catching events

As Apotomo triggers the event in the widget tree, the widget classes are one place to define observers.

class PostsWidget < Apotomo::Widget
  responds_to_event :tagClicked, :with => :filter
 
  def filter
    replace :state => :display
  end
 
  def display
  # ... and so on

I love Apotomo’s simple event system.

Again, two new steps.

  • Calling responds_to_event sets the observer. In case of fire, it invokes the #filter state method.
  • The #filter state itself just calls the #display state which collects posts and renders. The #replace helper method simply wraps the rendered view in a jQuery replace statement. Note that you may do that yourself – it’s up to you to emit any Javascript.

Now, the tag filtering works in the browser.

That’s all we need to write in order to have an AJAXed widget! It simply works, without any magic at all.

Apotomo is stable. Use it.

The framework we used here has been around for years but evolved from a “Model-driven architecture beast” into a small, stable widget framework based on Cells.

It is meant for RIA projects, dashboards, web desktops, well, Apotomo is here for helping you writing great widget-based web frontends, in a monolithic Rails environment.

Let’s write a Reusable Sidebar Component in Rails 3!

Monday, November 15th, 2010

This is a real world example how to use Rails Cells, the popular gem for creating reusable view components. The following post is clean and all-ages. Let’s just all be friends, no bashing, no f-words today, just a brief HOWTO.

It is different from what you might have learned from Rails so far. This doesn’t mean it is wrong. Just think about it. If you feel it’s shit, let me know. If you like this approach, I wanna know as well.

What are sidebar elements?

Usually reoccurring components like a “Recent posts” box in a blog application are what we refer to as sidebar element.

The exemplary blog application with a reusable sidebar element.

The exemplary blog application used in this post(s) can be found on github and runs with Rails 3.

So what we do today is a sidebar box. It contains

  • links to a certain subset of recent posts
  • tags to click, which will filter the post list

No partials and helpers today

As we’re learning a new paradigm today, we’re not gonna do the traditional approach to implement the box. Using partials and helpers might do it as well, but, let’s look forward.

The first step is to generate a cell, which exposes the same properties as a real controller.

blog$ rails g cells:cell Posts recent --haml
      create  app/cells/posts_cell.rb
      create  app/cells/posts/recent.html.haml
      create  test/cells/posts_cell_test.rb

Ok, a cell class, a view, a test. Great.

In the second step, I want to render a list of recents posts. My file app/cells/posts_cell.rb looks like this.

class PostsCell < Cell::Base
  def recent
    @posts  = Post.recent
    render
  end

Like a controller.

Cells are controllers.

So what do we do here?

  • We aggregate the items to display by delegating to the model.
  • A call to #render instructs the cell state to render its view in app/cells/posts/recent.html.haml.

The view is simple as well.

%h3 Recent Posts
 
%ul
  - for p in @posts
    %li #{link_to p.title, p}
  • We simply iterate over the posts and link to the real article.
  • Note that we can use helpers, logic, everything in cells views.

As a last step, we render the cell in the application layout.

%body
  %h1 The Incredible Cells Blog
 
  #sidebar
    = render_cell :posts, :recent

That’s all for creating a render-only sidebar component. You could have done this with your traditional tools. However, we already got a couple of benefits.

  • The cell is reusable throughout your project and even between different projects. Just plug the app/cells/posts directory into another app and you’re done. I will post separately about that.
  • No controller pollution as the cell computes and renders in its own separate instance.
  • We have better testability – another post on that one, promised!

Have a tag-cloud widget

One of Cells strength is when it comes to writing composed widgets. The tag cloud sitting above the recent posts list should be a separate cell state – meaning a separate method and a view.

class PostsCell < Cell::Base
  def recent
  # ...
 
  def tag_cloud
    @tags = Post.tag_counts_on(:tags)
    render
  end
end

Not hard to see that we might need another view in app/cells/posts/tag_cloud.html.haml.

- tag_cloud(@tags, %w(css1 css2)) do |tag, css_class|
  = link_to tag.name, "?tag=#{tag.name}", :class => css_class

Yeah, we can even use helpers from other gems, like the acts_as_taggable_on helpers. We’re not limited in any way, dude.

To actually show the tag cloud inside our box, let’s plug the tags into the recent.haml view for now.

%h3 Recent Posts
 
= render :state => :tag_cloud
 
%ul
  - for p in @posts
    %li #{link_to p.title, p}

Wow, we basically can embed actions within actions – this is fuc… simply great.

Interaction, babe!

When clicking a tag the “Recent posts” list should update, showing only posts matching that tag. This is something called interactivity – the cell in your controller view processes user gestures!

Not a big deal. And, if you think this is breaking MVC: it is not. This is MVC.

Let’s see how the cell controller handles that.

class PostsCell < Cell::Base
  def recent
    tag     = params[:tag]
    @posts  = tag ? Post.tagged_with(tag) : Post.recent
    render
  end
 
  def tag_cloud
  # ...
end

The cell controller is exactly the place where this VC-gluecode should live. We don’t need work-arounds like presenters or helpers here, we prefer true MVC.

Discussion

We just learned the basic usage of Cells, including

  • Generating and writing simple render-only cells.
  • Composing nested cells by calling render :state in cell views.
  • Processing user input by using #params in the cell state.

And we got plenty of stuff to check out, like

  • Caching cells to boost your application performance and simultaneously improving your architecture.
  • Writing functional tests and unit tests for cells to create reliable components that can be plugged into any controller and just work!
  • putting cells into Rails engines to maximize your modularity. Imagine real widgets for a blog application shipped as gems and running seamless in your views.

Now, comment! And, hey parents: Writing posts without using swearwords SUCKS!