Finding bugs with irb

2 Jan 2007

There has been a lot of irb love happening lately, and I’m lovin’ the irb, too.

After launching a Rails e-commerce application recently, I was taking a look through the database just to make sure things were working as expected. Lo and behold, I found a problem. Something funky was happening with a small number of the orders. Time to dig in.

The problem centered around calculating discounts, which calculations can be affected by a number of variables present at the time of checkout: the particular items in the cart, the discount code used, etc. In other words, it would be somewhat difficult to work out what should have happened versus what actually happened by taking the relevant data and doing the calculations by hand. In this case, it would be much easier to actually poke at the transactions in question and play with the code as it would have interacted at the time of the transaction. Rails console to the rescue!

$ ./script/console
  >> irb Sale.find(:first, :conditions => "something’s not quite right")
  >>

What’s that you say? Invoking irb from inside irb? Madness! What does it do? It loads another session inside your current session, and now self points to the results of that Sale.find. Why is this so useful? Well, suppose you have an instance method in the Sale class that does a lot of calculations, pulling in the related discount, related line items, etc., and it has references to self.this and self.that all over the place in there. With a little help from this irb sub-session, now you can play with that code as it was written, and (in this case) as it was executed against the instance when the instance was first created.

So, with this powerful tool in hand, and a little time poking at the discount calculations, I found my problem, wrote a test that reproduced it, fixed it, and repaired the affected transactions. Yay irb!



How to email reports from Rails

28 Dec 2006

Would you like to have a simple and painless way of sending reports from your Rails application via email? Any substantial web application will require some reporting, and the e-commerce application I’m working on is no exception. I recently received a request to send a daily report of the previous day’s sales via email. Here’s one way to do it quickly and easily.

The actual report generation is in a class I set aside specifically for reports called Report. It does some SQL tricks to pull out nicely-formatted data for the date of interest. All I have to worry about at that point is sending that data every day via email. Here’s my notifier code:

class Notifier < ActionMailer::Base
    def sales_for_yesterday
      require ‘FasterCSV’

      @from = ‘someone@example.com
      @recipients = ‘someone@example.com
      @sent_on = Time.now
      @yesterday = 1.day.ago
      @body = { :yesterday => @yesterday }
      @subject = "Sales Report"

      attachment :content_type => "text/csv", :filename => "sales_#{@yesterday.to_date}.csv" do |a|
        a.body = FasterCSV.generate do |csv|
          csv < < (fields = ["artist", "product", "variant", "unit price", "qty sold", "total"]).map {|f| f.titleize }
          Report.sales_for_date(@yesterday).each do |row|
            csv << fields.map {|f| row[f] }
          end
        end
      end
    end
  end

The fun part is the attachment generation. The Rails API documentation doesn’t explain all the options you can send the attachment method — it simply shows you how to pass the desired content-type as a text argument. My example shows you how to specify the file name for the attached file by passing in a hash of options to the attachment method. I use the block to add the content to the attachment on the fly, generating it with FasterCSV. This wouldn’t work as well with huge amounts of data, since it would all be in memory, but for a daily report it’s just fine.

I generate the CSV file by picking the fields of interest from the report, prettying them up with titleize, then making that the first row of the file. The rest of the rows are created by iterating over the results from a method in my Report class and then iterating over the field list to make sure the data gets populated in the correct column order.

The only thing left to do is invoke the mailer every day. I do that with a one-line cron job that is executed daily:

RAILS_ENV=production /path/to/app/script/runner Notifier.deliver_sales_for_yesterday

Easy as pie.



How to serve protected downloads with Rails

24 Nov 2006

Do you have a site where you sell downloads? Perhaps you sell e-books, screencasts, or MP3s. Would you like a way to protect these downloads by using your Rails application to authenticate users before they can download the file, but you don’t want to tie up a Rails process to actually serve the file? Lighttpd’s mod_secdownload was built specifically for this situation, but there’s a little gotcha for those of you who are also using mod_proxy to pass traffic to mongrel…

Read the rest of this entry »


Penultimate Rails E-commerce Book Update

4 Nov 2006

I was hoping that this would be the final book update, but I just haven’t had the time yet to write the last big chunk that’s left to be written: Integrating with payment gateways using Active Merchant.

So, instead of keeping people waiting, I decided to make this release, which isn’t quite as big as I was hoping it would be. I did toss in some fun stuff, though, like how to use the dollars_and_cents plugin for storing money amounts in the database and the acts_as_sluggable plugin to help with SEO for your store. You can check out the full list of changes, and of course, you can also buy it now!

Oh, and now you can even buy it without using PayPal, if you wish. I have set up Google Checkout so you can purchase it that way, although I currently don’t have the integration set up to automatically send the book to you after you cough up the dough. Perhaps I’ll get around to getting Google Checkout better integrated, and then I could add info on that to the book. :) Until then, if you use Google Checkout you’ll have to be a little patient, giving me time to get the notification email and send you the book manually.



Book update coming soon

25 Sep 2006

I’ve gotten a few emails asking about when the next update to my Rails e-commerce book will be available, so I thought I’d post some information here about that.

My target time frame for the next release is some time in October, probably later rather than sooner. In fact, it may even slip into early November, though I definitely don’t want to go any later than that. The reason for the delay is not related to writing the book, but rather to some of the other projects that have popped up recently.

Well, there is one delay that’s due to the content of the book, and that’s the PayPal information I want to include. In my next update (which may actually be the final update), I want to add more information about shipping, handling addresses, and handling payments. With regards to payments, I intend to write specifically about PayPal, and I’m hoping that I’ll be able to provide better information about integrating Website Payments Pro with Rails. I think the situation is better than it was a few months ago when I first wrote about it, so I need to do some research on that in hopes of providing a better solution.

If you have some suggestions for me on what content you’d like to be added to the book, either as enhancements to topics already covered or entirely new topics, please feel free to contact me directly or leave a response here letting me know what you’d like to see. I’ll do my best to accommodate requests.