Read my latest article: 8 things I look for in a Ruby on Rails app (posted Thu, 06 Jul 2017 16:59:00 GMT)

Be Careful that you don't Stub your Big Toe

Posted by Tue, 13 Feb 2007 06:09:00 GMT

In a project that I’m currently working on, we’re handling recurring payments for subscribers. I’ve decided to play with a different payment service API on this project (TrustCommerce), which supposedly has one of the easier systems to handle recurring payments as well as one-time charges to the same credit cards. They store all the credit card data so that our delivered product to the client is CISP-compliant.

I came across the TrustCommerce Subscription plugin for Rails, which does just everything that I need to do in this first product release… as well as things that aren’t requirements just yet.

Well, I got my test account from TrustCommerce and was working on some RSpecs to test my new subscription and noticed that it was failing. After some snooping around the error responses, I realized that… test accounts don’t give you the ability to test the Citadel features of TrustCommerce. It’ll be another week or so before finish getting our account setup, so what am I to do? I really want to finish writing these specs and move on to the other portions that are dependent upon this working.

Suppose that you were going to perform something like this in an AR callback.


class BillingDetail < ActiveRecord::Base

  # validations    

  before_create :store_credit_card_data_with_trust_commerce

  private 

    def store_credit_card_data_with_trust_commerce
      # some of this is still test data... prettyu much copied from the README
      # TODO: refactor... but keep me out of controllers!
      response = TrustCommerceGateway::Subscription.create(
          :cc =>  self.credit_card_number, 
          :exp => '0412', 
          :name => self.customer_name,
          :amount => 1,
          :cycle => '1y',
          :demo => 'y'
        )

      if response['status'] == 'approved'
          self.billing_id = response['billingid']
        else
        # handle failure
        end
    end
end

Enter Mock Objects

Since I am unable to succesfully use the TrustCommerceGateway::Subscription.create method until I get our real account, I needed a simple way to emulate the interaction with the web service.

This can be done by using a Mock object, which RSpec provides for you.


TrustCommerceGateway::Subscription.stub!(:create).and_return( {expected response} )

Let’s look at the following spec file (much of it removed to protect the innocent).


module ValidBillingDetail
  def valid_attributes
    { # a hash of valid key/values for this model }
  end

  def approved_trust_commerce_subscription
    { 'status' => 'approved', 'billingid' => '1093423' } 
  end
end

context "A new billing detail" do
  include ValidBillingDetail

  setup do
    TrustCommerceGateway::Subscription.stub!(:create).and_return( approved_trust_commerce_subscription )
  end

  # bunch of other specs

  specify "should store new billing info with 3rd party API and store the billingid" do
    @billing_detail = BillingDetail.create( valid_attributes )
    @billing_detail.billing_id.should_not_be nil
  end
end  

You’ll notice a few things. First, you’ll see that I’ve stubbed the create method and when it is called in the method in my model, it’ll return the hash that I’ve specified.

TrustCommerceGateway::Subscription.stub!(:create).and_return( approved_trust_commerce_subscription )

In the spec, you will see that I am checking that that the .billing_id.should_not_be nil. If you look back in the method in the model above, you will notice that an approved subscription returns a billing_id, which is set when the transaction is successful.

This is working out great for me and because the documentation is fairly easy to follow, I’m going to be able to mock much of the behavior that I’ll be using in the application, without needing to even connect to their API.

If you’re using RSpec, I highly encourage you to read more about mocks objects.

RSpec Bundle for TextMate

Posted by Mon, 12 Feb 2007 12:58:00 GMT

Just a quick follow up to my post last night, Sharing Custom TextMate Bundles with Subversion. It appears that I missed the RSpec bundle for TextMate, which is listed on the RSpec webpage.

Install the RSpec Bundle

Installation is quite simple, just change directories to your TextMate bundle directory.


    $ cd ~/Library/Application\ Support/TextMate/Bundles/

Check out the RSpec bundle from the subversion repository.


    $ svn co svn://rubyforge.org/var/svn/rspec/trunk/RSpec.tmbundle
    # lots of files...
    A    RSpec.tmbundle/Support/spec/fixtures/example_failing_spec.rb
    A    RSpec.tmbundle/Support/spec/fixtures/example_passing_spec.rb
    A    RSpec.tmbundle/Support/spec/spec_mate_spec.rb
    Checked out revision 1489.

Now, just reload your bundles in TextMate and you’re good to go!

Bundles > Bundle Editor > Reload Bundles

I’d like to thank Aslak Hellesøy for pointing me to this and for also providing me with the correct subversion URL, which is currently outdated on the RSpec page until the next release.

Poke My Brain

Posted by Mon, 12 Feb 2007 06:42:00 GMT

I’m working on a few blog articles that I’ll be posting over the next few weeks. The other day, I got another email from someone that asked me if I would write about something that I mentioned briefly in a blog post. This got me thinking… perhaps there are things that you’d like me write something on? In general, I try to keep a broad range of topics that relate to Ruby/Rails circulating and I’m planning a major overhaul to my blog (switch to mephisto in the near future?) and working on more tutorials, especially as we near the release of my book as a O’Reilly Rough Cut… and when it finally makes it to print. :-)

If there is something that you’d like to learn more about (Rails, business, agile…), feel free to drop an email to suggestions@robbyonrails.com.

Gems Gone Wild!

Posted by Mon, 12 Feb 2007 06:27:00 GMT

Mike Clark is offering everyone1 in the Ruby community Mardis Gras beads… in exchange for showing everyone your sexy gems. Chad and Bryan showed us theirs, so I figured it was my turn to show you all what I’ve been hiding beneath this shell.


    # gem list|grep '^[a-zA-Z]'
    actionmailer (1.2.5)
    actionpack (1.12.5)
    actionwebservice (1.1.6)
    activerecord (1.14.4)
    activesupport (1.3.1)
    asset_compiler (0.2)
    BlueCloth (1.0.0)
    builder (2.0.0)
    camping (1.5)
    capistrano (1.4.0, 1.3.1, 1.2.0)
    capistrano-ext (1.1.0)
    cgi_multipart_eof_fix (2.0.2)
    cheat (1.2.1)
    chronic (0.1.6)
    color (0.1.0)
    daemons (1.0.3, 0.4.4, 0.4.2)
    diff-lcs (1.1.2)
    facets (1.4.5)
    fastercsv (1.2.0)
    fastthread (0.6.2)
    feedtools (0.2.26)
    flexmock (0.5.0)
    gem_plugin (0.2.2, 0.2.1)
    gen (0.41.0)
    glue (0.41.0)
    google-geocode (1.2.1)
    gruff (0.2.8)
    hoe (1.1.6, 1.1.2)
    hpricot (0.5.110, 0.4.86, 0.4, 0.2)
    livejournal (0.3.1, 0.3.0)
    markaby (0.5)
    metaid (1.0)
    mocha (0.4.0)
    mongrel (1.0, 0.3.13.4, 0.3.13.3)
    mongrel_cluster (0.2.1, 0.2.0)
    needle (1.3.0)
    net-ping (1.2.0)
    net-sftp (1.1.0)
    net-ssh (1.0.10)
    nitro (0.41.0)
    og (0.41.0)
    payment (1.0.1)
    piston (1.2.1)
    postgres (0.7.1)
    quickbooks (0.0.2)
    rails (1.1.6)
    rake (0.7.1)
    rc-rest (2.1.0)
    rcov (0.7.0.1)
    RedCloth (3.0.4)
    rmagick (1.14.1)
    rspec (0.7.5, 0.7.4, 0.7.0, 0.6.4)
    ruby-breakpoint (0.5.0)
    ruby-growl (1.0.1)
    rubyforge (0.3.2, 0.3.1)
    RubyInline (3.6.2)
    shipping (1.5.0)
    sources (0.0.1)
    superredcloth (1.160)
    sydparse (1.2.0)
    syntax (1.0.0)
    tattle (1.0.1)
    unicode (0.1)
    uuidtools (1.0.0)
    xml-simple (1.0.10, 1.0.9)
    ZenTest (3.4.3, 3.4.1)

Perhaps it is time to run some updates. Been running off of Rails edge forever and never remember to update those gems. :-)

puts his new beads on…

1 Okay, maybe I lied about the free beads… ;-)

Sharing Custom TextMate Bundles with Subversion

Posted by Mon, 12 Feb 2007 04:35:00 GMT

Early last year, I began to start creating a bunch of snippets and such for TextMate, all of which were lost several months ago due to Hurricane iSight. I recently decided to start building some again, especially some that sped up my RSpec writing. After creating a few, I wondered, “would anybody else on my team want to help me write some?” So, I thought that it was time to figure out how to share my bundle with others and allow them to add stuff to it… which seems like a good job for Ms. Subversion.

I couldn’t find a quick walk-through online and found myself in the #textmate IRC channel getting proper instructions. (thank you Allan!)

Create Your Bundle

In TextMate, you can open up the Bundle Editor and create a new bundle. Let’s call our custom bundle, RSpec. Go ahead and begin adding some snippets, commands, etc to your new custom bundle. Once you have something in your Bundle, you’ll want to reload your bundles, by going to Bundles > Bundle Editor > Reload Bundles. This will write your new bundle to disk to ~/Library/Application\ Support/TextMate/Bundles/.


    $ ls -al ~/Library/Application\ Support/TextMate/Bundles/
    total 0
    drwxr-xr-x   5 robbyrus  robbyrus  170 Feb 11 21:10 .
    drwxr-xr-x   4 robbyrus  robbyrus  136 Feb 11 20:11 ..
    drwxr-xr-x   5 robbyrus  robbyrus  170 Jan 12 16:58 PLANET ARGON.tmbundle
    drwxr-xr-x   3 robbyrus  robbyrus  102 Feb 11 21:10 RSpec.tmbundle
    drwxr-xr-x   4 robbyrus  robbyrus  136 Oct 21 13:38 Robby Russell???s Bundle.tmbundle

Importing your Bundle into Subversion

You’ll want to first import your new bundle into Subversion.


    $ cd ~/Library/Application\ Support/TextMate/Bundles/
    $ svn import RSpec.tmbundle/ -m "Initial import of RSpec (test) bundle" http://{respository_url}/{repository_name}/RSpec.tmbundle/
    Adding         RSpec.tmbundle/info.plist
    Adding         RSpec.tmbundle/Snippets
    Adding         RSpec.tmbundle/Snippets/new specification.tmSnippet

Great, now it’s in Subversion. Now, you’ll want to check it back out so that TextMate is running off of the version from Subversion.

The simplest way to do this is to delete your local copy and checkout the latest from Subversion.


    $ rm -rf RSpec.tmbundle/; svn co http://{respository_url}/{repository_name}/RSpec.tmbundle/
    A    RSpec.tmbundle/Snippets
    A    RSpec.tmbundle/Snippets/new specification.tmSnippet
    A    RSpec.tmbundle/info.plist
    Checked out revision 5.

All that you need to do now, is relaod your bundles again. Now that you know where the bundle files are stored, you can commit any changes as they are made.

Committing Bundle Changes

When you make changes to your TextMate bundle, you can do the following to commit your updates to the Subversion repository.

See Your Pending Changes

You can change directories to your custom bundle and run svn status.


    $ cd ~/Library/Application\ Support/TextMate/Bundles/RSpec.tmbundle/
    $ svn status
    ?      Snippets/new context.tmSnippet

You’ll see that the new snippet that I created needs to be added to Subversion.


    $ svn add Snippets/new\ context.tmSnippet 
    A         Snippets/new context.tmSnippet

Now, let’s commit it to the repository.


$ svn ci -m "Adding new context snippet" 
Adding         Snippets/new context.tmSnippet
Transmitting file data .
Committed revision 6.

At this point, all Subversion tips and tricks apply… so… it’s time to leave it to you to figure out the rest. :-)

TIP: Always reload your bundles before and after running svn update or svn commit

...and there you have it! You and your friends can (with a little work) share and develop your own custom bundles for TextMate. I’m hoping to get my teammates at PLANET ARGON to help me build a bunch for RSpec, which I’ll try to release into the wild soon. If anybody is already working on RSpec snippets and other TextMate hacks, please let me know.

UPDATE

Aslak kindly commented on this post and has pointed me to bundle available in the RSpec subversion repository, which I blogged about.) :-)

Happy hacking!

Extending ActionController, part two

Posted by Fri, 09 Feb 2007 13:57:00 GMT

One of our consulting clients consists of a team of .NET developers that are rewriting a rather large product in Ruby on Rails. Every once in a while they have a problem that needs a second set of eyes to look over in order to find a solution with Rails. One of their developers recently asked how they could extend ActionController to provide all of their controllers with an action that would interact with a custom extension they built for ActiveRecord.

One of the few examples that he found to help them do this was a short blog post that I wrote nearly two years ago, titled, Extending ActionController. Given that I wouldn’t do it that way anymore, I felt that I’d quickly post an updated way of doing something similar.

Create Your Extension

This is when you get to take advantage of that lonely lib/ directory in your Rails application. We’ll go ahead and save our custom extension as lib/giraffe_actioncontroller_ext.rb. Now let’s put some code in there.

5

Looking at the following example, you’ll notice that we’re creating a basic Ruby module, which contains a method named, hot_air_balloon. Within that method, we can do just about anything that we’d normally do in an controller action.


# lib/giraffe_actioncontroller_ext.rb
module PlanetArgon
  module Giraffe
    # add your custom methods here
    def hot_air_balloon
      #
      # if some_condition_in_request?
          render :text => 'the giraffe left in a hot air balloon'
      #end
    end
  end
end

Great, however it’s not going to do anything yet. We need to wire our custom module into ActionController. To do this, let’t go ahead and place the following code at the bottom of lib/giraffe_controller.rb.


# include our custom module in ActionController::Base
ActionController::Base.class_eval do
  include PlanetArgon::Giraffe
end

Now that this file exists, we need to tell Rails about it.

Require Your Extension

You’ll want to update your environment configuration by adding the following to config/environment.rb


# Include your application configuration below

require 'giraffe_actioncontroller_ext' 

That’s all there is to it. Now you can do fun things like…


class ApplicationController < ActionController::Base
    before_filter :hot_air_balloon
    #...
end

Unhiding Actions

As I mentioned, our consulting client needed a handful of methods available to all controllers for use within actions, but they also wanted one method to be accessible via external requests. It turns out that all methods are, by default, hidden from the action processor. Basically, their names are stored in an array, named, hidden_actions. So, to remedy this, they were able to delete their action from the array.

A quick way to do this, is to update lib/giraffe_actioncontroller_ext.rb... like so.


# include our custom module in ActionController::Base
ActionController::Base.class_eval do
  include PlanetArgon::Giraffe
  hidden_actions.delete 'hot_air_balloon'
end

Now every controller in your application has an awesome hot_air_ballon action, which your giraffe friends can use to cruise the night skies in harmony.

8

Happy coding (and flying)!

1 Artwork and stories were created by several members of the PLANET ARGON team. I’m not sure why they killed me off in the first issue… or why they removed my thumbs in the story… only to discover hidden giraffes?

Older posts: 1 2 3