Skip to main content

Mobomo webinars-now on demand! | learn more.

If you've upgraded to the recently released jQuery 1.5 you may have heard about the fancy new AJAX facilities that allow you to define things like this:

var jax = $.ajax({   url: '/some/url' })  jax.success(function() {   alert("It worked!");") });

Well, that new power is known as Deferreds and it can be useful in more places than straight-up AJAX callbacks. If you want an in-depth look at the Deferred API you can look at the jQuery Documentation or read this very in-depth look at the API. But we're here today to take a look at a few practical examples that will let you really get the most out of the new functionality.

A More Expressive setTimeout

I've always hated the Javascript API for setTimeout. In my opinion it just doesn't make sense to have the duration come after the function. Using Deferreds, we can write a very English-friendly syntax for timeouts.

$.wait = function(time) {   return $.Deferred(function(dfd) {     setTimeout(dfd.resolve, time);   }); }

Now, thanks to the Deferreds, I can write timeouts in my app like this:

$.wait(5000).then(function() {   alert("Hello from the future!"); });

This is just a small example, but it shows you how easy it is to write deferred functionality into your applications. For our next trick, let's get a little more complex.

Pretty Little Wrapper

A common thing I find myself doing in jQuery is writing a small wrapper for an API. I always hate how messy the callback code gets, let's see if we can clean it up a bit using Deferreds.

Twitter = {   search:function(query) {     var dfr = $.Deferred();     $.ajax({      url:"http://search.twitter.com/search.json",      data:{q:query},      dataType:'jsonp',      success:dfr.resolve     });     return dfr.promise();   } }

Now I can easily perform Twitter searches in my app like so:

Twitter.search('intridea').then(function(data) {   alert(data.results[0].text); });

The Advantages of Deferreds

Why would I want to use deferreds instead of standard callbacks? Well, for one, you can attach multiple callbacks to a deferred, giving you lots of flexibility in designing your application. Another way they're superior is by giving you built-in error handling. If you had a deferment that failed, you would be able to handle that as well:

function doSomething(arg) {   var dfr = $.Deferred();   setTimeout(function() {     dfr.reject("Sorry, something went wrong.");   });   return dfr; }  doSomething("uh oh").done(function() {   alert("Won't happen, we're erroring here!"); }).fail(function(message) {   alert(message) });

Deferreds are just a simple and powerful tool for you to use to make your code cleaner, more readable, and more functional. This is really just scratching the surface, so if you have any other fun Deferred tricks, I'd love to see them in the comments!

Update: From the comments, I see that it is appropriate to return dfd.promise() instead of the deferred object itself. The code has been updated to reflect as much.

Categories
Author

I've been using Git for almost a year now, but I didn't really start using Git until recently when I began working for Intridea.  Once I started using Git on a daily basis, dealing with multiple projects, and multiple branches per project, I would occasionally make the mistake of changing code on the wrong branch.  While annoying, it was easily fixed by stashing the changes and applying the stash to the proper branch.

As much as I love git stash, this began to get old, and constantly hitting up git status to check the current branch wasn't cutting it.  After a bit of googling,  It describes how to add the current branch name and its clean/dirty status to you terminal prompt.

Just add this to your .bash_profile:

function parse_git_dirty {
  [[ $(git status 2> /dev/null | tail -n1) != "nothing to commit (working directory clean)" ]] && echo "*"
}
function parse_git_branch {
  git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* (.*)/[1$(parse_git_dirty)]/"
}

export PS1='u:[33[31;40m]w[33[0;33m]$(parse_git_branch)[e[0m]$ '

And you should end up with something that looks like this:

As you can see, I like to use a bit of color to help things stand out.

So far this has been immensely helpful.  With this info at a glance, I always know where I am and how I last left things.

Categories
Author

Others have talked about people being "searchers" or "filers" when it comes to e-mail. I think the same thing applies to hard drive organization, and I'm definitely a searcher. I don't have much in the way of organization in my folders short of basic overarching functional categories (Documents, Pictures, Rails, etc). Right now my Documents folder has 365 items in it and absolutely no canonical organization strategy. However, it rarely takes me more than a few seconds to find what I'm looking for at any given point. The secret? I just sort my files by date.

Categories
Author

First the database migration used in all examples (using Rails 2.0 sexy migrations):

class CreateClassifications < ActiveRecord::Migration    def self.up      create_table :classifications do |t|        t.integer :parent_id        t.integer :lft        t.integer :rgt        t.string  :name        t.text    :description        t.timestamps      end    end      def self.down      drop_table :classifications    end  end

Please note that the left and right columns are named in such a way that they will not conflict with database reserved words commonly used in join statements.

Then the code:

class NestedSet < ActiveRecord::Base    acts_as_nested_set      def self.all_parents      self.roots.map do |root|         (root.full_set.collect {|child| child if child.children.size > 0}).compact.flatten      end    end      def self.all_leaves      self.roots.map do |root|         (root.full_set.collect {|child| child if child.children.size == 0}).compact.flatten      end    end    end

This code works - but works slowly and yields horrific SQL. The reason it's slow and horrific is because you need to hit each node in the tree to test for it's number of children. This is less than ideal especially if you need to do this regularly (or on a tree with hundreds of nodes) - which leads us to the next iteration:

class NestedSet < ActiveRecord::Base    acts_as_nested_set      def self.all_parents      self.find(:all, :conditions => "rgt <> lft + 1")    end      def self.all_leaves      self.find(:all, :conditions => "rgt = lft + 1")    end    end

This works much better and is far more efficient. Each call to the class method makes a single query to the database. The reason the we can do this is because of the way nested sets work. A good explaination of this can be found in the BetterNestedSet README:

An easy way to visualize how a nested set works is to think of a parent entity surrounding all  of its children, and its parent surrounding it, etc. So this tree:      root      |_ Child 1        |_ Child 1.1        |_ Child 1.2      |_ Child 2        |_ Child 2.1        |_ Child 2.2    Could be visualized like this:      ___________________________________________________________________     |  Root                                                             |     |    ____________________________    ____________________________   |     |   |  Child 1                  |   |  Child 2                  |   |     |   |   __________   _________  |   |   __________   _________  |   |     |   |  |  C 1.1  |  |  C 1.2 |  |   |  |  C 2.1  |  |  C 2.2 |  |   |     1   2  3_________4  5________6  7   8  9_________10 11_______12 13  14     |   |___________________________|   |___________________________|   |     |___________________________________________________________________|     The numbers represent the left and right boundaries.  The table then might  look like this:       id | parent_id | lft  | rgt  | data      1 |           |    1 |   14 | root      2 |         1 |    2 |    7 | Child 1      3 |         2 |    3 |    4 | Child 1.1      4 |         2 |    5 |    6 | Child 1.2      5 |         1 |    8 |   13 | Child 2      6 |         5 |    9 |   10 | Child 2.1      7 |         5 |   11 |   12 | Child 2.2

You can also check out additional nested set explanation in an article titled "A Nested Set Implementation..." (paying special attention to the illustrations in section #3).

Going back to our example, there's one more thing we can to do make this one step better - move our methods into the plugin implementation. This makes sense as our class methods are not directly related to our application logic and pertain mainly to nested set behavior.

You can add a version of our methods to the nested set plugin by adding to the ClassMethods module in better_nested_set.rb in the lib folder of the BetterNestedSet plugin with the following:

def parents    acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:right_column]} <> #{acts_as_nested_set_options[:left_column]} + 1)", :order => "#{acts_as_nested_set_options[:left_column]}")  end    def leaves    acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:right_column]} = #{acts_as_nested_set_options[:left_column]} + 1)", :order => "#{acts_as_nested_set_options[:left_column]}")  end

Or if you're savvy you can just apply the patch I created that includes these methods along with documentation and tests:

  • download the patch
  • move the patch to the root of your BetterNestedSet plugin
  • patch -p0 < leaves_and_parents_class_methods.patch

I've also added the patch as an enhancement to the BetterNestedSet trac.

On a recent project when I was using the BetterNestedSet plugin to manage a large hierarchal set of data, I encountered a problem that required me to find all of the items in a nested set that had children and those that didn't. In nested set terms I wanted: all 'parent' nodes and all 'leaf' nodes that exist within the 'tree'.

If you want to do this through the current BetterNestedSet interface you might be tempted to do something like this:

Categories
Author

I know that most Rails developers have come across the problem of notifying people by email that they have an internal message on your app’s own messaging system. Usually this is easy enough, and elegantly done in your model by using

class InternalMessage < ActiveRecord::Base   after_save :notify_person_of_new_internal_message      protected   def notify_person_of_new_internal_message      MyMailer.deliver_new_posting(self.from_person, self.message)   end end 

However, let’s consider a situation where you need duplication of data on two different processes. For example, if you would like to generate a notification message when some posts to a common forum. The quick way to do this would be by calling two separate methods in your controller, like so:

subject = "Ted Stevens has posted a new topic" body = "From Ted Stevens: " +         "'I hope you get this, the tubes have been acting up recently!'" @person.save_to_inbox(subject, body) MyMailer.deliver_new_posting(@person, subject, body) 

This requires you to generate the subject and the body of the message and use the methods to work out the logic.

However, with a little ActionMailer hackery, you can make this scheme much cleaner.

MyMailer.notify(person, :new_posting, from_person, note) 

In your model,

class MyMailer < ActionMailer::Base   class << self      def notify(person, method, *params)         new_mailer = new         new_mailer.create!(method, *params)         mail = new_mailer.mail         person.save_to_inbox(mail.subject, mail.body)         deliver(mail) if person.wants_email_notification?      end   end    def new_posting(from_person, note)      from from_person.email      subject "#{from_person.name} has posted a new topic"      @body[:from] = from_person      @body[:note] = note   end end 

Next, in views/my_mailer/new_posting.rhtml

From <%= @from_person %>: <%= @note %> 

The following three lines generate a new MyMailer object, create the email specified by the method (in this case, :notify_posting) using ActionMailer’s create! method (which in turn uses Ruby’s glorious send method), and pull out the TMail object that ActionMailer sends to the SMTP server. Conveniently, the TMail object lets you extract out the subject and body, which lets you map them to your InternalMessage class.

new_mailer = new new_mailer.create!(method, *params) mail = new_mailer.mail 

The above code generates the email, pulls out the generated subject and the body and uses it as the subject and body of the internal message. The idea is that the content of both the email notification and the internal email match up. This method does not require you to setup your subject and body. Instead, this method lets you use ActionMailer as a rendering framework for generating text/html for all of your internal messages. DRY is Good!

Categories
Author
Subscribe to Tips