AJAX Tabs (Rails redux)
A while back I wrote a tutorial on AJAX Tabs as a plug for a PHP clone of Ruby on Rails called Biscuit. Well Biscuit is long gone, but the I still use the tutorial code, but just in Rails. So I came up with an update using Rails. Check out the Ruby on Rails AJAX Tabs Tutorial.
eCommerce on Rails @ Feb PhillyOnRails
Credit Card Processing with ActiveMerchant
So for anyone interested in Rails based eCommerce I’ll be presenting on the subject at PhillyOnRails this Monday February 26th, at Drexel. I’ll be presenting on Credit Card Processing with ActiveMerchant. So anyone keeping up will know that I’m psyched about the fact that ActiveMerchant 1.0.0 was just released.
Secure Database Storage with Sentry
I’m also going to try to cover Secure Database Storage with Sentry if I have time. This is a controversial subject for eCommerce because you’re not supposed to store certain types of information related to a transaction (for example CVV). Sentry makes asymmetric encryption a cinch. That means you can take super secret information along with an order or transaction and encrypt it for later retrieval by the merchant. All the merchant needs to do to access the secret is provide his private key similar to PGP/GPG or SSH. This beats the heck out of a lot of eCommerce methods.
The very popular PHP based osCommerce production code actually stores full credit card information in the database if you aren’t using a gateway. Of course newer beta versions don’t store the card number in database, but they email them unsecured to the merchant. That sucks.
So you might be saying “who doesn’t use a gateway?” Merchants that don’t ship products automatically or will make order adjustments, or have some other special after order process that has to be manually handled.
acts_as_paranoid_versioned or acts_as_versioned + acts_as_paranoid
I know what you are thinking, and yes this is the best title I could come up with: acts_as_paranoid_versioned does the trick.
A question to the PhillyOnRails mailing list prompted me to get around to this one.
acts_as_versioned and acts_as_paranoid are two really great plugins that make enterprisey|auditable|accountable rails based projects much easier.
acts_as_versioned stores changes made to records in a separate table for historic purposed, think wiki entries, order processing, cms pages, inventory, etc.
acts_as_paranoid overrides the destroy and finder methods in order to “delete” object but keep data around in the database. This is perfect for wiki entries, order processing, cms pages, inventory, etc.
Problem
Unfortunately using both plugins causes version records to be destroyed even though the base model keep the record around (setting deleted_at).
The problem with using them both lies in acts_as_versioned’s implementation. acts_as_versioned dynamically creates a versioned class then adds has_many in your base model. The plugin naturally relies on rails to handle cleanup for an object with :dependent => :delete_all. I say naturally because you really wouldn’t want old versions of a destroyed object hanging around… unless of course you did want old versions of a destroyed object hanging around.
“I want to use both acts_as_versioned and acts_as_paranoid to create an audit trail!”
So here’s the fix…
Code
Add this to config/environment.rb
module ActiveRecord
module Acts
module Versioned
module ClassMethods
def acts_as_paranoid_versioned
acts_as_paranoid
acts_as_versioned
# protect the versioned model
self.versioned_class.class_eval do
def self.delete_all(conditions = nil); return; end
end
end
end
end
end
end
Then instead of calling both acts_as_versioned and acts_as_paranoid call acts_as_paranoid_versioned in your model.
class Example < ActiveRecord::Base
acts_as_paranoid_versioned
end
Have your cake and eat it too
“Yay, it works!”
With this setup, the versioned record doesn’t pick up deleted_at. If you want to do that or add any other special functionality, change
def self.delete_all(conditions = nil); return; end
to
def self.delete_all(conditions = nil)
# foo
end
Recommendations for acts_as_versioned
Make version_association_options available to override. At current, version_association_options gets set then class_eval puts it into action creating the callback for before_destroy. If version_association_options were placed outside the acts_as_versioned class method (it’s own method or attr) it would be much easier to override the delete_all behavior. For example: self.version_association_options.delete(:dependent)
