Archive for the 'Ruby on Rails' Category

CurbFu – Now With Killer Testing!

May 20, 2009

Matt Wilson and I have been making some awesome new updates to CurbFu – our convenient wrapper for Ruby’s curb gem – itself an wrapper around libcurl.

Our latest improvement revolves around integration testing. At Greenview Data, we have several Rack apps that talk to each other, including a Rails app. While all of code for the individual apps was unit tested, we still lacked a good integration test to make sure everything played well together.

In the past I had tried to set up a VM instance that was controlled by a series of RSpec Story Runner tests. Getting the test server instances updated and running was a pain, managing all of the running processes was a pain (especially testing a system with down processes), and writing tests to verify data became quite contrived.

With the introduction of Bryan Helmkamp’s Rack::Test and Rails 2.3’s support for Rack, I dreamed of having these apps running in memory, able to send HTTP requests to each other without having to set up a separate integration testing system. Now that all of our apps use CurbFu to send HTTP requests to each other, we seized the opportunity to create a testing module that override’s CurbFu’s get/post/put/delete operations. Instead of sending a real HTTP request over the internet, CurbFu will now call any rack apps you specify directly using Rack::Test.

Essentially, this system is similar to FakeWeb and Webrat’s newly added Rack support, but the difference is that if you use CurbFu for all of your HTTP communication, you can quickly and easily set up an integration test environment or set up smart mocks of HTTP services.

How does it work?

require ‘curb-fu’
CurbFu.stubs = {
‘a.example.com’ => RackApp1.new,
‘b.example.com’ => RackApp2.new
}
class RackApp1
def call(env)
CurbFu.get(’http://b.example.com’)
end
end
class RackApp2
def call(env)
puts “WOW!”
end
end
CurbFu.get(’a.example.com’)
#=> WOW!

require 'curb-fu'

CurbFu.stubs = {
  'a.example.com' => RackApp1.new,
  'b.example.com' => RackApp2.new
}

class RackApp1
  def call(env)
    response = Rack::Response.new
    response.status, response.body = [200, '']
    CurbFu.get('http://b.example.com')
    response.finish
  end
end

class RackApp2
  def call(env)
    response = Rack::Response.new
    response.status, response.body = [200, "WOW!"]
    response.finish
  end
end

puts CurbFu.get('a.example.com').body
#=> WOW!

Loading a Rails app is a bit more involved:

require 'curb-fu'
require '/path/to/rails/app/config/environment'
require 'dispatch'

CurbFu.stubs = {
  'my.cool.railsa.pp' => ActionController::Dispatcher.new
}

We’ve set up a series of Cucumber stories to test the interplay between our various rack apps. By having the rails app in memory, we’re able to access ActiveRecord objects from our step definitions, as if we’re within the rails app. We’re also able to stub specific methods on objects within our rack apps and we throw up quick little Rack apps that can pretend to be things like a Solr server or a site hosting an RSS feed. The sky is the limit!

Once caveat we’ve run into is the issue of namespacing. It may be a good idea to namespace your Rails model classes as they may conflict with other loaded Rack apps.

Have fun testing!

Links:
CurbFu

BackgrounDRb 1.0.4 – Considerations

July 18, 2008

Today I gleefully updated BackgrounDRb to 1.0.4 after I learned that a new release was out that supported clustered BDRb servers.  I quickly learned that regiester_status has been removed.  That’s right.  All that code that sends data from your workers to your app need to be refactored to put data into cache[job_key].  This approach is more thread-safe, however.  Perhaps you could even write your own wrapper that puts data into cache on a call to register_status.

All in all, however, there are some really cool new features related to clustering.  I was starting to think for a while that BDRb had been abandoned and that Bj was the new way to go.  This release clearly puts BackgrounDRb on top for spawning asynchronous tasks.

Linux Editor Update

May 1, 2008

Well, no sooner than I had written the previous article, did I consider NetBeans.  At this point I was willing to try anything, so I downloaded the special Ruby distribution and gave it a whirl.  One of the prereqs was the Java 1.6 runtime, a hefty download.  As NetBeans opened for the first time, I was greeted with a splash screen with a progress bar inching along as various Java libraries were loaded.  This did not bode well!  My bloat-meter was starting to register.  

However, once NetBeans was up and running, I found it to be pretty intuitive and it runs very well.  Response to input is instantaneous and the editor does a good job of not getting in the way.  I really enjoy the SVN integration as well.  It’s very easy to ignore files and perform the usual updates/commits.  The merging tool has some of the slickness of Apple’s FileMerge and many of the features of my favorite diff tool, Beyond Compare.

My only beef so far is that auto-complete is invoked with CTRL+space and I don’t think you can map it to TAB and still be able to use TAB for its original purpose.  The autocomplete also only works by selecting items from a drop-down.  It won’t just guess what you want.  

But overall, NetBeans has been my favorite Linux text editor for Rails.  However, I think I’ll have to stick with gedit or Eclipse for my Perl editing.

Ruby/Rails on Linux (oh yeah, Perl too)

April 26, 2008

So I’ve spent the last four months developing Rails apps, Ruby scripts, and Perl scripts on a Fedora desktop. I cut my teeth with Ruby/Rails on my Mac at home, so I was in on the TextMate and Growl goodness. It’s comical to see that 90% of Rails developers are on the Mac, and one would assume that it’s because if one must use a trendy framework, they must also choose a trendy development platform. The truth is, I just haven’t found sufficient analogues to Mac tools in the Linux environment.

The first editor I experienced (and the one I keep coming back to) is Eclipse/Aptana/RadRails. It is a beast of an IDE, taking several seconds to load on a capable dual core AMD 64. Here’s some other issues I run into on a daily basis with the 1.0 release (which, to me, would imply feature complete and stable):

  • RadRails “forgets” about syntax highlighting and makes everything purple.  Sometimes, typing space at the end of a line and saving will fix it, but it’s a crap shoot.
  • Eclipse will occasionally slow down to a crawl for about a minute.  The GNOME task monitor says the CPU is idle, but Eclipse would make you think it was sharing CPU time with a nuclear explosion simulator.
  • The “go to resource” dialog doesn’t quite load results for every file that matches your criteria.  It also takes an extra arrow key press to get through the list.
  • If left open for too long, the inevitable, “There was an error, would you like to exit the workbench?” dialog appears.  You can say “no” but then you’re just living on borrowed time.  Eventually, it will all come crashing down.
  • Of course, there are not nearly as many cool shortcuts and scriptability that TextMate offers.
After getting frustrated with RadRails, I turned to gedit, GNOME’s text editor.  Apparently, there are several plugins you can get to make it act almost like TextMate.  It’s also very lean and responsive.  First of all, the gedit website was down when I tried to get the plugins.  Then, it became a confusing ordeal to get the plugins installed correctly.  Gedit also liked to keep backups of each file sitting right next to the real files.  This made SVN a bit messy when I would just run an svn commit on everything.  Furthermore, the plugins, like the quick file open, didn’t even work 100%.  After some gedit crashes, I decided to ditch it and look further.
After trying the two major open source editors, I looked into ActiveState’s Komodo IDE.  It’s a paid app running at $300.  This IDE was the most consistent, stable, and feature-rich app out there.  However, it had major performance issues.  Simply scrolling through the list of files in a project slowed the app to a crawl.  I installed the version compiled with gcc 5, which offered a slight speed improvement, but still wasn’t snappy enough to facilitate rapid development.  It wasn’t worth $300.
So now I’m back to Eclipse.  Yes, I know there’s always vi and emacs, but I’m feeling too lazy right now to learn all the keystrokes required for things as simple as highlighting text and switching files.  I’d rather just use the mouse that God gave me.
As far as a Linux analogue of Growl, there is Mumbles.  At this point, it seems like too much of a hassle to find all of the plugins to make Mumbles work with even simple services/apps.  I love how many apps now (like Firefox 3) have Growl support built right In.  
Which brings me to my point.  The Mac is sort of like a “GUI on Rails.”  Its API sets stricter conventions on how an app should work, but with those limits comes the benefits of simply getting things done and the ability to focus on the grander issues – like interoperability and bleeding edge features.  In the Linux world there is an amazing freedom of choice, but with it comes chaos and a lot more work that goes toward just getting things to talk to one another.  While the freedom is nice, sometimes it’s nicer to work within stricter guidelines and get something done quickly.

    Happiness

    April 21, 2008

    A book I still have to read is [ed. I think it was called] The Science of Happiness whose author was interviewed recently on NPR.  The interviewers discussed the emerging branch of psychology that is studying happiness.  It got me thinking about how perceived happiness is a major market factor and how people now days are more willing to pony up extra cash and make an effort to buy your product or service if it causes them some happiness beyond the satisfaction of having a need met.  

    There are so many examples of this:

    Apple is the most obvious candidate.  Sure, you can buy and build a computer using the same parts Apple does for half the cost.  You can install Linux for free or pay for Windows and get your work done.  Why are people paying more for Macs?  The Mac OS and Apple’s software suites offer a more user-friendly and, ultimately, satisfying experience.  Apple’s users (like me) are happier.  

    37 Signals recently posted about Zingerman’s deli in Ann Arbor and the philosophies they follow that make them a great company.  Yes, you pay $20 for a reuben and a root beer, but the experience of going to the deli outshines many other casual eating experiences.  Customers are showered with free samples of exotic foods and the staff are very personable.  The selection of products is also far beyond what you’d find in many other places.

    This also brings to mind Ruby on Rails.  There are plenty of other MVC frameworks out there that do the same exact thing as Rails.  But there are so many positive externalities that Rails offers that put it above the rest: the community, the Ruby language itself, and the way agile development is baked into the framework and its related plugins.  It really makes for a pleasant development experience.

    The bottom line is that Americans are becoming more willing to pay for products that make them feel better.  This has positive repercussions where a product can benefit the natural environment or society as a whole.  The challenge is to build a brand that offers that extra bit of happiness and (ideally) really does change the world for the better.

    Three Weeks of XP

    February 14, 2008

    I’ve moved on from a job cowboy coding (read: shoot from the hip, work alone) ASP.NET websites to a job working at an anti-spam software company using Ruby on Rails, Perl, and sendmail under an agile/eXtreme Programming methodology. It’s heavenly bliss! Definitely worth the hour drive to Ann Arbor each day.

    I’m finding that I’m much more productive working with a programming partner. Something about working side by side really spurs me on. When you work with people with open minds (and have an open mind) it’s a continuous learning and improvement process. It also minimizes the stupid mistakes that slow you down as you have another pair of eyes on the situation. Not only do I learn new techniques and ideas from others, but it also helps me to coalesce ideas that I know intuitively, but gain a better understanding by having to explain them.

    Working with Ruby on Rails is also a joy. It’s great to be able to whip out features in a matter of hours and spend more time on testing and polishing. Perl, well, it’s no Ruby. It’s definitely better than C, but given the choice, I’d go for Ruby.

    Ditching Windows has improved my life. I think my blood pressure has gone down. My workstation runs Fedora. Now I don’t have to worry about antivirus software causing my user interface to crash. It’s no Mac OS, but any sort of UNIX works for me.

    I’ve also enjoyed the company pool table and the coolness that is Ann Arbor!

    Back to an Old Friend

    January 14, 2008

    Last year I set up my old Athlon 850 as a MythTV (both front and back-end) box. With a PVR-150 and a PVR-250 installed, it was a passable DVR running Mythdora. During our transition to Michigan, it fell out of use. One day I tried to upgrade to MythTV .20 but the Mythdora installation that supported it did not allow me to use the older NVidia drivers and so it would freeze up when XOrg launched. When DataDirect started charging for channel listings. I gave up on the project completely. I put my PC into permanent retirement.

    But then, like the Army coming back to ask John Rambo for help, I coaxed my old PC to help me one more time. Its mission: to run IEs4Linux to aid in some part-time freelancing. I tried to install MythTV .19 and have my MythTV along with IEs4Linux, but the LVM volume kept corrupting for some reason. I then installed Fedora Core 4 and now everything is running beautifully.

    While I had signed up for some shared hosting for my dkast.net domain, the service has proved to be unreliable, so I’ve just decided to host my own sites. It’ll be a better learning experience, too, as I’ll get to work with git, capistrano, and perhaps mongrel/nginx.

    Once you get Linux working, it really is a pleasure to work with.

    Next step: find a way to get my Airport Express to act as an ethernet-to-wireless bridge and WDS repeater simultaneously.

    Eager Loading

    December 1, 2007

    One thing that made me uneasy about Rails’ ActiveRecord was how it handles associations. For instance, say I have a table of products in the database and another table listing comments about the products. So, for each product we have many comments.

    Back in the good ol’ ColdFusion days, I would write a query that joins the two tables. Then I would loop through each field and have some funky conditional statements, like the following:

    <cfset prevProductId = 0 />
    <cfloop query="qryProductsWithComments">
     <cfif product_id neq prevProductId>
      ...if this is not the first product, finish printing the previous product's template...
      ...we've hit either the first product or a new product, so print out the beginning of the product template and the first comment...
     <cfelse>
      ...this is another comment, so print out just another comment...
     </cfif>
     <cfset prevProductId = product_id />
    </cfloop>

    That’s pretty darn confusing, but it was better, performance-wise, than executing a new query every time you iterate over the products loop, like so:

    <cfloop query="qryProducts">
     ...spit out the product template...
     <cfquery name="qryComments" ...>
      SELECT * FROM comments WHERE product_id = #qryProducts.product_id#
     </cfquery>
     <cfloop query="qryComments">
      ...spit out a comment...
     </cfloop>
    </cfloop>

    By default, ActiveRecord will perform similarly to the latter example. However, with eager loading, you can get the same performance as the former example without all of the confusing if statements:


    # in our model:
    class Product < ActiveRecord::Base
     has_many :comments
    end


    # in our controller:
    class ProductsController < ApplicationController
     def index
      @products = Product.find(:all, :include => :comments)
     end
    end


    # in our view:
    <% for product in @products -%>
     <%= render :partial => "products/product" %>
     <% for comment in @products.comments -%>
      <%= render :partial => "comments/comment" %>
     <% end -%>
    <% end -%>

    So much cleaner! And easier!

    With ASP.NET 2.0, you’re pretty much stuck doing the equivalent of the second CF example using the server controls or you have to build your own object data source that will work similarly to ActiveRecord, but you’ve just spent an hour or so reinventing the wheel.