1. Skip to navigation
  2. Skip to content

The ELC Community Blog

A knowledge exchange on Ruby on Rails and Agile Development

December 21, 2007

by Daniel Lunde

Notify me when it's done

Here's a fun little tip I got while working with my client. Occasionally, when we have to run some really long processes (eg. reloading a production snapshot or running some lengthy migration), it's nice to be notified when that process is done.

Quick and dirty notifications

1) For aural feedback simply add " && say 'All Done'"

$ mysql app_dev < dump.sql && say "Finished importing"

2) For growl feedback add " && growlnotify -s -m 'All Done'"

$ mysql app_dev < dump.sql && growlnotify -s -m "Finished importing"
* The -s makes the notification stick around until you click it.
* More info about growlnotify below.

Pass or fail notifications

The purpose of && between the two commands is so that the notification will only occur if the first command is successful. You could take that a step more and send different notifications depending on the return status of the command.

$ (cmd && say "Success") || say "Failed"
$ (cmd && growlnotify -s -m "Success") || growlnotify -s -m "Failed"
* Parenthesis are important.

If you don't care about whether a command succeeds or not, you could just replace && or || with a semicolon.

$ cmd; say "Don't care how it finished, but it did"

Installing growlnotify and a Leopard hack

growlnotify is not installed by default with growl, but it's easy to install.

  • Download Growl (http://growl.info/downloads.php) and open the dmg.
  • Execute the command: '/Volumes/Growl 1.1.2/Extras/growlnotify/install.sh'.
    * The Growl version may be different for you.

If you are using Leopard, there's a bug with growlnotify as of version 1.1.2 that prevents growlnotify from working consistently. However, there's an easy workaround.

  • Open up the Growl preference pane and select the Network tab.
  • Click to enable "Listen for incoming notifications".
  • Now when you run growlnotify, add the "-H localhost" option.
$ cmd && growlnotify -s -H localhost -m "Success"

A bit messy, but it works every time.

December 17, 2007

by Ryan Garver

OpenSocial on Rails, finally 1.0

Hooray! We have a 1.0 of our opensocial_container plugin. Pick it up here:

ruby script/plugin install http://opensocial.rubyforge.org/svn/plugin/tags/1_0_0/opensocial_container

I've also created a STABLE tag. If you want to use that use the following:

ruby script/plugin install http://opensocial.rubyforge.org/svn/plugin/tags/STABLE/opensocial_container

In this release I completely refactored the Javascript library to get around a weird bug in Prototype. Apparently synchronous Ajax (Sjax?) calls are a little buggy and occasionally don't return. Now all requests back to the server go through normal asynchronous requests. This could still use some tuning down the road, as the requests are still in sequence. Eventually I'll get them running in parallel and taking advantage of some client caching.

Another improvement is now the route addition no longer takes a subdomain, but rather a full hostname and the instance id is prepended as a subdomain of the provided host. So for example, if you put the following in your config/routes.rb file:

map.opensocial_container 'example.com'

The container will use the hostname of '.example.com'. So if my instance_id is 342, the IFRAME that is embedded will point to '342.example.com'. This will require some configuration on the part of your webserver to accept these subdomains. This is pretty ugly, and needs to be cleaned up, but it works for now. I modeled this off of the google.com/ig site which attaches these ids to gmodules.com.

December 10, 2007

by Dylan Stamat

Testing without the database

Everyone seems to have their own opinion about "when" and "if" they should omit hitting the database in their test suites.

The "why" boils down to the time it takes to run test suites... as database contention obviously adds for some longer runs.

The "how" is through mocking/stubbing, which then brings up the mixed opinions on the matter.

Controllers

While I was writing up a summary about this, I realized Mike Clark already did the good deed, and jotted down both a concise overview "and" personal opinions from a bunch of bright cats :) I urge you to read the following posts... and taking the time to follow the corresponding links in the article. His two part article is one that everyone should read:

Part 1 , Part 2

Models

This is obviously a bit more controversial than the mocking/stubbing of controllers. I mean, using an inherent ActiveRecord object would warrant the entire driver/database implementation throughout your assertions... right ? Again... let the answer be an excersise to the reader.

UnitRecord by Dan Manges and friends uses schema.rb to create a mock of your models database columns.

It even adds an ActiveRecord::Base.disconnect! that you can throw in your test helper, which will raise if you dare try and connect to your database in your unit suite.

Rick Olson has something "somewhat" similar in ModelStubbing

Personal

With all that said... I'm personally a fan of mocking/stubbing controllers, and letting my model tests hit the database. My controller tests should route requests, alter session / flash state, and manipulate models. The model manipulation doesn't matter here, and these tests belong in my unit/model tests.

I will still take the performance hit, and let my unit/model tests hit the database.

In the end, it's currently a matter of preference and discretion. If I happen to come up with a crazy corner case in my controllers... I may want the database involved. If my model tests became un-reasonably slow, I'd look at mocking/stubbing or cleaning up some of my test cases (with caution).

Would love to hear your opinions on this... and maybe Mike will gather up the troops and do some similar posts in regard to the model side of things :)

December 07, 2007

by Yuanyi Zhang

acts_as_chattable: make web chatting easy

ELC Plugins

acts_as_chattable is a plugin which allows you to integrate a user-to-user chatting system into your Rails app in minutes.

Installation
script/plugin install http://svn.elctech.com/svn/public/plugins/acts_as_chattable
Demo
svn co https://svn.elctech.com/svn/public/demo/acts_as_chattable
Usage

At first, I assume you have a ‘User’ model and it own a ‘name’ method which will return user‘s chatting name. If you don‘t have these yet, create them and let‘s go!

1. Install Juggernaut, acts_as_chattable needs Juggernaut to get PUSH support.

script/plugin install svn://rubyforge.org//var/svn/juggernaut/trunk/juggernaut

2. Generate chat_controller.

script/generate chattable

3. Render chat in views

<%= render_chat(user, friends) %>
<%= buddy_list(friends) %>
  • user should be current_user which will be used to create a Juggernaut channel.
  • friends should be an array of user which presents current user's friends.

You can use chat_link(friend) to generate buddy_list customly, it will return a link which will open a chat window with this friend.

More documents are available at:http://letrails.cn/plugins/acts_as_chattable

4. At last, Don‘t forget to start push_server.

ruby script/push_server
ruby script/server

5. It's done! Open your browser and start chatting.

Comments and feedback are welcome!

A Chinese version is also available here.

December 07, 2007

by Ryan Garver

OpenSocial Container 0.3.0

ELC Plugins

This is getting out a little later than I intended, but I did want to make a formal announcement. As of this point the plugin supports all three persistence types: Global, Instance, and Person. The last remaining piece of the core JS API to be implemented is activities. I'm trying to get 0.4.0 with activities in before the weekend. I'm hoping that sometime next week I will have a publicly working version of the container in one of our deployed clients.

To install:
ruby script/plugin install http://opensocial.rubyforge.org/svn/plugin/tags/0_3_0/opensocial_container

December 03, 2007

by Ryan Garver

OpenSocial Container 0.2.0

ELC Plugins

New version of the container is up. This adds support for global persistence, and a way to set owners and viewers. See the README for details.

To install:
ruby script/plugin install http://opensocial.rubyforge.org/svn/plugin/tags/0_2_0/opensocial_container

December 01, 2007

by stevend

Mephisto Flickr AJAX Loader

I'm tired of waiting for my blog to load because of a slow flickr feed request! I designed this new plugin by copying the flickr photostream plugin, but making it actually load the pictures and the feed through an immediate AJAX request. This tremendously increased the performance of my mephisto pages!

The plugin defines a flickr controller, which accepts the AJAX request. Unfortunately, you can't change how the photos are laid out anymore (I'm not setting up a liquid context for this ajax response). Of course, if you don't like the result of the plugin, just change it to match what you want:

class FlickrController < ActionController::Base
  def index
    result = ""
    pics = find_pictures
    pics.each do |pic|
      result << "<a href='#{pic.link}'><img src='#{pic.send(params[:format].to_sym)}' alt='#{pic.title}'></a>"
    end

    render :inline => result
  end
end

How to install and use

  • Uninstall the flickr photostream plugin
  •    1  ./script/plugin install http://wush.net/svn/public/plugins/mephisto/mephisto_flickr_ajax
    
  • Use the following tag in your liquid template:
       1  
       2  {{flickrajaxphotostream feed:<your_feed_url> count:</your_feed_url><number_images> format:<[square, small, etc]>}}<br />
       3  {{endflickrajaxphotostream}}
       4  </number_images>
    
  • Also posted on flouri.sh

December 01, 2007

by Ryan Garver

OpenSocial? What's that?

I have been digging pretty deep in to the OpenSocial API. My interest has been mainly focused on the building of the containers which hold the OpenSocial applications. There is a lot on confusion about what OpenSocial is and why it is interesting. I'll be honest, it took me a bit of searching to really understand what OpenSocial is and how it is organized. I'll try and explain the what, a little bit of the how (more will come later), and my impression of the why it is interesting and might succeed. You already know the who (Google), where (the Interweb), and when (November 1, 2007-present).

What is OpenSocial?

OpenSocial is an API. Actually, it's two types of APIs. First, the REST API is designed to export the profile, friendship, activity, and persistence components to the social network (or any other application where these principles can apply) implementing the API. Second, the Javascript API is geared towards "OpenSocial Applications" and effectively does the same thing as the REST API, but in the form of a set of Javascript classes and functions.

The Application

The OpenSocial Application deserves some further clarification. At the 10,000 foot level an OS App is similar to Facebook Applications. The format is taken from the iGoogle gadget. It boils down to an XML file which includes metadata and wraps the HTML and Javascript that is ultimately rendered to the user. Here is a sample from Last.fm's OpenSocial Application (http://www.last.fm/opensocial/myfavouritemusic.xml):

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="My Favorite Music">
    <Require feature="opensocial-0.5" />
    <Require feature='setprefs' />
    <Require feature='dynamic-height' />
  </ModulePrefs>
  <Content type="html">
  
  <![CDATA[

  <div id="overlord">
  
    <div id="loading">Loading...</div>
    <div id="updating" style="display:none;">Updating...</div>
    <div id="area"></div>

    <div id="lastfmAccount" class="lastfmAccount">
        <div id="hadALastfmAccount" style="display:none;" class="strongLinks">
          <p><a id="haveAccountLink" href="javascript:;" onclick="$('setUsername').toggle();_IG_AdjustIFrameHeight();new Effect.ScrollTo('setUsername');return false;">Have a Last.fm account? Click here.</a></p>
        </div>
        <form id="setUsername" style="display:none;">
          <input type="text" id="username" />
          <input type="submit" value="That's me!" />
          <span id="cancelChangeUsername">| <a href="javascript:;" class="cancel" id="">cancel</a></span>
        </form>
    </div>
    <div id="placeholder"></div>

  </div>

  <style>
    @import url(http://cdn.last.fm/opensocial/main.5.css);
    @import url(http://cdn.last.fm/opensocial/canvas.1.css);
  </style>
  <script type="text/javascript" src="http://cdn.last.fm/javascript/lib/prototype.js"></script>
  <script type="text/javascript" src="http://cdn.last.fm/javascript/lib/scriptaculous.js"></script>
  <script type="text/javascript" src="http://cdn.last.fm/javascript/source/flashplayer_inline.js"></script>
  <script type="text/javascript" src="http://cdn.last.fm/javascript/11/flashpreview.js"></script>

  <script src="http://cdn.last.fm/opensocial/lfm.2.js"></script>
 
  ]]>
  </Content>

</Module>

What makes this so neat? Well, the widget now has access to your profile, your friends, your activities within the Host Network.

The Container

An OpenSocial Container is any website that allows its users to select, configure, and embed OpenSocial Applications in to some part of the site, usually a profile page. The container must understand the XML file format for the applications and implement the OpenSocial Javascript API. Some OpenSocial Containers include: LinkedIn, Plaxo, and Orkut. For the purposes of this article I've broken the Container concept in to a Host Network (LinkedIn, Plaxo, Orkut), and the Container (the actual IFRAME which powers the Application).

How does it work?

The OpenSocial Container boils down quite simply to an IFRAME with the text of the <Content> element from the application's XML dumped in to the body. One difficulty for building a container is dealing with the security risks of exposing cookies set by the "Host Network" to the Application's content, since the Host is doing the embedding. To ensure privacy and a certain degree of security the Container needs to originate from a different domain name than the Host. By doing this the Host/Container (they are the same entity) trick the browser into protecting the Host cookies from the Container's (and thus the Application's) Javascript.

The Container also makes extensive use of AJAX to request data from the Host/Container. This is how the Application gets access to the profile, friendship, activities, and persistence information.

Why do this? Why should we care?

OpenSocial standardizes social networking APIs. That alone is not particularly novel. But this is Google we're talking about here. With that kind of backing and buzz this may stick. As a developer this means that you only need to learn one API to be able to build social applications. One particularly interesting aspect of the OpenSocial API is the persistence layer. Using this portion of the API a developer can, quite easily, create a full featured interactive application which is entirely self contained in a single static XML file. All of the persistence and communication is handled by the Container and the Host. Now that is cool.

If this takes off like is appears to be poised to do, then we could be in for some excitement akin to the growth and fragmentation of the early social networks; except this will be happing above the social network layer. One interesting possible side effect will be a growth in the popularity of niche social networks. OpenSocial appears to lower the castle walls of the established networks. I expect the crossover in data and user-base between networks will skyrocket as once "proprietary" profile data becomes easily moved and shared.


home | services | Ruby on Rails Development | code | blog | company