[Rails 2.3] Adding a "phase" to the ActiveRecord Lifecycle

I've run into a situation where it seems to me that if I could "extend" the typical AR lifecycle to add another "phase" or step to it, it would simplify things. My problem is that I just don't know how to do that, and I haven't been able to find documentation anywhere on it!

I'm working on an e-commerce application that's somewhat complex. Due to constraints of the organization, I can't have accounts or authentication. My theoretical approach is to store an "order ID" in a user's session, and of course all selects/updates etc. will be only for that ID from their session, thus keeping the current status of the order in the database at all times. If it were something simple I'd just store an array of object IDs in the user's session, but there are several different kinds of products/services to buy, each with vastly different models and various requirements ("if you have this you must have that but MUST NOT have this", etc.).

The AR lifecycle question comes into play because I'd like to add some form of validation on the Order model, but ONLY before and after the user's card is charged.

So here's a simple example -

Order < ActiveRecord::Base   belongs_to :object   has_many :item_joins   has_many :items, :through => :item_joins   has_many :other_item_joins   has_many :other_items, :through => :other_item_joins

  # ... and so on ... end

Because the user can add multiple items and other items to their order, as well as set the "object" on their order at any point in the ordering process, I can't call the validations I want after save. I'd much rather have a before/after "card_charged" step in the lifecycle, and run a validation before the card is charged, then one after it's charged.

So, for example, I'd like to be able to do something like:

Order < ActiveRecord::Base   # ...associations as above...   before_charged :ensure_not_empty

  private   def ensure_not_empty     if self.items.count < 1 and self.other_items.count < 1       errors.add_to_base("Your order is empty!")       return false     end   end

And this would need to fire when Order#charge_card (or similarly named method) is called, canceling the call to Order#charge_card if false is returned.

I took a quick look at state machines (aasm), and I have to confess that I don't know much about a state machine or how one works other than very basic theory. It seems like it might be overkill to me, when all I want to do is add two methods to the lifecycle as above. However, I'm fully willing to consider the possibility that what I'm suggesting here is outside the realm of best practices.

Any ideas as to how I could add these steps to the lifecycle of just this object?

I think the best way would be to use a state machine, as you indicated yourself in a paragraph I snipped. Second best would be to use conditional validations, see the :if and :unless options on all the validates_something methods.

Michael