Enhancement to drop_receiving_element_js in ActionView::Helpers::ScriptaculousHelper

Today I submitted an enhancement ticket for the Rails ActionView::Helpers::ScriptaculousHelper module. This version of drop_receiving_element_js adds two additional options, beforeAjax and afterAjax, that provide a means for javascript code to be executed before and after the creation of the Ajax.Request object. This would allow greater flexibility than just having to create an onDrop function from scratch when needing to do more than making a remote request from within the function. The Rails API doesn’t actually include this method, instead, it’s called from the drop_receiving_element method. You can track the ticket on Lighthouse.

If you’d like to use this enhanced version immediately, create a file named scriptaculous_helper.rb to be placed in config/initializers (for Rails 2.x) or lib (for older versions of Rails). Save the code below into the file, restart your app, and you should be good to go.

  1. require 'action_view/helpers/javascript_helper'
  2.  
  3. module ActionView
  4. module Helpers
  5. module ScriptaculousHelper
  6. def drop_receiving_element_js(element_id, options = {}) #:nodoc:
  7. options[:with] ||= "'id=' + encodeURIComponent(element.id)"
  8. beforeAjax = options[:beforeAjax] ? options[:beforeAjax] + ';' : ''
  9. afterAjax = options[:afterAjax] ? options[:afterAjax] + ';' : ''
  10. options.delete(:beforeAjax)
  11. options.delete(:afterAjax)
  12. options[:onDrop] ||= "function(draggable,droppable,event){" + beforeAjax + remote_function(options) + ';' + afterAjax + "}"
  13. options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
  14.  
  15. options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]
  16. options[:hoverclass] = "'#{options[:hoverclass]}'" if options[:hoverclass]
  17.  
  18. # Confirmation happens during the onDrop callback, so it can be removed from the options
  19. options.delete(:confirm) if options[:confirm]
  20.  
  21. %(Droppables.add(#{element_id.to_json}, #{options_for_javascript(options)});)
  22. end
  23. end
  24. end
  25. end

Here’s an example call from one of my apps that I used to swap the order of an HTML element and make a remote call to change the affected objects’ attributes on the back end:

  1. drop_receiving_element("field#{@field.id}", :url => field_path(@field),
  2. :method => :put, :accept => 'fields', :hoverclass => 'droppable_field',
  3. :beforeAjax => 'droppable.parentNode.insertBefore(draggable,droppable);')

Posted on Sep 03, 2008 | filed under Ruby on Rails | 0 comments


What I learned today about Fibonacci Numbers

During high school and for a time in college, I hated job interviews. Looking back, I think it’s safe to say that fear, rather than pure hatred, caused me to turn an abhorrent eye toward these things. I just couldn’t stand the idea of getting dressed up just to have someone prick and prod my brain like cattle. Thankfully, as I have become more experienced professionally and I have grown more confident about my abilities, I have come to really enjoy the process.

So what does this have to do with Signor Pisano’s famous number sequence? Well, during a job interview some years back, I was tasked to write a function in ActionScript to calculate the Fibonacci number for a given order n in the sequence. When about twenty minutes later I still couldn’t solve the problem, my chances for further consideration were doomed.

After that nightmare, I was determined to figure out a solution on my own. Here’s the solution I came up with in Java, ignoring input verification:

  1. public int fib (int n)
  2. {
  3. if (n == 0) {
  4. return 0;
  5. } else if (n < 3) {
  6. return 1;
  7. } else {
  8. return fib(n - 2) + fib(n - 1);
  9. }
  10. }

It turns out that this is a standard solution to this little problem. So now I could go on my way confident that no interviewer will ever get me on that one again. I’ve even asked the same question a few times to potential candidates I’ve interviewed.

Because my current job gives me the flexibility to do so, this year I started taking a few CS classes at the University of Texas at Austin. I enjoy it very much, and my programming knowledge and skill have only improved as a result. Today was my first day of classes for the fall semester. This time around I’m auditing a one-hour course on Ruby and and I’m enrolled in a second-year course on data structures taught by Professor Gordon S. Novak where we’ll be tackling Lisp as well as a few other languages besides Java.

I’m already thinking that I like this guy when he begins a short intro on Lisp with an example function to calculate a Fibonacci number:

  1. (defun fib1 (n)
  2. (if (< n 2)
  3. n
  4. (+ (fib1 (- n 2))
  5. (fib1 (- n 1)) ) ) )

At this point I’m thinking, “I rock!”. He then pulls up an alternative solution, which I immediately proceed to ignore lest I spoil this moment of self-appreciation:

  1. (defun fib2 (n) (fib2b 0 1 n))
  2.  
  3. (defun fib2b (lo hi steps)
  4. (if (= steps 0)
  5. lo
  6. (fib2b hi (+ lo hi) (- steps 1)) ) )

Now on his laptop, he nonchalantly begins to compare the two solutions:

  1. > (fib2 1)
  2. > 1
  3. > (fib1 1)
  4. > 1
  5. > (fib2 2)
  6. > 1
  7. > (fib1 2)
  8. > 1

So far, so good.

  1. > (fib2 10)
  2. > 55
  3. > (fib1 10)
  4. > 55

So he keeps increasing slightly and then finally jumps to 200:

  1. > (fib2 200)
  2. > 80571172992510140037611932413038677189525
  3. > (fib1 200)

“What’s happening here?” he asks us. A few people call out that it’s still calculating.

“Do you think if we wait a few minutes, we’ll get the answer?” Silence.

“Do you think it’ll finish by the end of the hour? The day? This year?”

He then takes a moment to explain how scientists believe that the earth has about 6 billion years or so left until it gets gobbled up by an expanding sun, “at which point this program will have yet to calculate the solution.”

Gasp! All of my dreams of becoming the next Bill Gates dashed in an instant! The problem with little fib1 is that for every call to itself, two additional calls are being made. Thus we have an illustration such as this:

n           fib1
|          /    \
|       fib1     fib1
|      /    \   /    \
|   fib1  fib1 fib1  fib1
V   /  \  /  \ /  \  /  \

So as n increases linearly, the number of calls to itself increases exponentially. What does this give us in terms of Big O? The dreaded O(2n).

Therein is a simple, yet powerful example of the importance of understanding algorithm analysis. While this example may not be immediately applicable to my job, dealing with performance issues is at the heart of what a web developer does, so I’m happy for the lesson.

Posted on Aug 28, 2008 | 0 comments


Simple Regular Expression to Replace Non-instantiated Fixtures

Today I wanted to update my unit test to use instantiated fixtures, and I found this regular expression useful for replacing the non-instantiated fixture syntax fixture(:name) with the instantiated syntax @name.

I used the following pattern to find references to the non-instantiated fixtures:

\w+\(:(\w+)\)

I used the following pattern to replace each match with an instantiated fixture.

@$1

Posted on Aug 26, 2008 | 0 comments