Saving TMail into an ActiveRecord model
Thu Nov 22 17:00:18 -0800 2007
ActiveRecord works well when we are saving strings and integers, but what if you want to save a real, live, honest-to-God Ruby OBJECT like a TMail::Mail instance?? Well.. serialize to the rescue!
Today I had an interesting need.
I am making an Email transfer system, which, in part, needs to be able to save an Email for later inspection, retrieval or queries.
While this system is not a Ruby on Rails app, I decided to use ActiveRecord anyway as it is an awesome database interface, plugged in with a local copy of SQLite3, I had my entire datastore handy.
The system that this is replacing stores the objects on disk using Ruby’ marshalling methods, but ActiveRecord has a much cleaner implementation for use when you are saving to and from a database, it is invoked using the serialize method.
So, in my case I have a class called Email, which, when you create it with a raw source of an email text, initializes itself and parses that email text into a TMail::Mail object which it stores as an ActiveRecord attribute.
So, I wrote a spec like this:
1 2 3 4 5 6 |
email_text = IO.read("#{File.dirname(__FILE__)}/../fixtures/raw_email") it "should create a tmail object as a TMail::Mail object" do mail = {:email => email_text} mail.email.class.should == TMail::Mail end |
To make this pass:
1 2 3 4 5 6 7 |
require 'tmail' class Email < ActiveRecord::Base def initialize(email) super self.email = TMail::Mail.parse(email[:email]) end end |
OK, that passes, pretty straight forward.
But now, what if I call:
1 2 3 |
mail.save mail = Email.find(:first) mail.email.class #=> String |
So that doesn’t work, what I want is to be able to save that object to a database, and then, when I recall it from the database, have the same model I started with.
OK, so first, we’ll write a spec for that:
1 2 3 4 5 6 |
it "should save itself to the and serialize it's mail component" do mail = create_email mail.save! mail = Mailer::Email.find(:first) mail.email.class.should == TMail::Mail end |
That fails, now we use the serialize method of ActiveRecord.
To do this, you need to make the “mail” record of the Emails table a TEXT field. This is important.
Then we go into the class definition and add the following:
1 2 3 4 5 6 7 8 9 10 |
require 'tmail' class Email < ActiveRecord::Base serialize :email def initialize(email) super self.email = TMail::Mail.parse(email[:email]) end end |
With that serialize :email, the ActiveRecord class will convert the TMail object into a text string through YAML and save it to the database as a text string. When it recalls it from the database, it will read this string via YAML and reinstate the object in all it’s ruby glory.
Pretty handy!
blogLater
Mikel


Mon Apr 13 09:23:46 -0700 2009
Is there a way to save the email to the database as raw text instead of in YAML format?
thx.