Let us say you are applying rails application for any snowboard rental store.

Confirmed snowboard could be in a single of three states:

  1. away for maintenance
  2. offered at store X
  3. on loan to customer Y

The organization must have the ability to notice a rental history for

  • a specific snowboard
  • a specific customer

The rental history must include temporal data (e.g. Sally leased snowboard 0123 from 12 ,. 1, 2009 to 12 ,. 3 2009).

How does one design your model? Would you've got a snowboard table with 4 posts (id, condition, customer, store), and copy rows out of this table, together with a timestamp, to some snowboard_history table each time the condition changes?

Thanks!

(Note: I am not really attempting to implement accommodations store it was only the easiest analogue I possibly could think about.)

I'd use a set of plug ins to complete the job. Which may use four models. Snowboard, Store, User and Audit.

acts_as_state_machine and acts_as_audited

AASM simplifies the condition transitions. While auditing produces a brief history you would like.

The code for Store and User is trivial and functions_as_audited will handle the audits model.

class Snowboard < ActiveRecord::Base

  include AASM
  belongs_to :store


  aasm_initial_state :unread
  acts_as_audited :only => :state

  aasm_state :maintenance
  aasm_state :available
  aasm_state :rented

  aasm_event :send_for_repairs do
    transitions :to => :maintenance, :from => [:available]
  end

  aasm_event :return_from_repairs do
    transitions :to => :available, :from => [:maintenance]
  end

  aasm_event :rent_to_customer do
   transitions :to => :rented, :from => [:available]
  end

  aasm_event :returned_by_customer do
    transitions :to => :available, :from => [:rented]
  end
end

class User < ActiveRecord::Base
  has_many :full_history, :class_name => 'Audit', :as => :user,
   :conditions => {:auditable_type => "Snowboard"}
end    

Presuming your customer may be the current_user throughout the controller action when condition changes that's about that.

To obtain a snowboard history:

@snowboard.audits

To obtain a customer's rental history:

@customer.full_history

You might like to produce a assistant approach to shape a customer's history into some thing helpful. Maybe something similar to his:

 def rental_history
    history = []
    outstanding_rentals = {}
    full_history.each do |item|
      id = item.auditable_id
      if rented_at = outstanding_rentals.keys.delete(id)
        history << { 
          :snowboard_id => id, 
          :rental_start => rented_at,
          :rental_end => item.created_at
        }   
      else
        outstanding_rentals[:id] = item.created_at
      end
    end
    history << oustanding_rentals.collect{|key, value| {:snowboard_id => key,  
      :rental_start => value}
  end
end