Day 4: Model layer
The database problem is solved. My limited understanding pins the failure on my pre-set “id” attribute. Currently I’m setting :id manually after calling the superclass (ActiveRecord::Base) constructor and before saving the object, which appears to work.
A second problem occurred when I saved objects more than once, specifically when the ID is the same but non-key fields changed. I got around this by doing an update if the ID exists in the database and a save if it does not. This results in an extra query with every save, but caching is done so rarely that this should not make a difference
app/models/person.rb constructor:
def initialize( person_info )
if person_info.instance_of? Basewrapper::Recordwrapper
hash = person_info.get_hash
id = hash["id"]
super hash
write_attribute :id, id
if Person.exists? id
update
else
save
end
end
end
Timeentry, Project and Company look very similar to this. To create basic associations, I declare that Project and Person “has_many :timeentries” and Timeentry “belongs_to” Project and Person.
I added the custom attribute “api_user” to the basecamp objects. This will allow me to clear the cache for each user at the end of the session.
I also added the static function “update_cache(url, login, pass, use_ssh)” to every model object. The cache will be initialized when the user authenticates, and this will be our only basecamp interaction. All subsequent data is read from my local database.
Where this is going:
Once the model layer is complete, I will write the controller layer to generate graphs of hours per person, hours per project and (if I have time) a pivot view of hours by person by project.

Philipp,
I am really impressed with your work you are describing : great job, keep going.
So did you really end up producing an ActiveRecord implementation for Basecamp, or did you just gather inspiration from ActiveRecord’s approach ?
Maybe you should take a look at ActiveSalesforce (http://rubyforge.org/projects/activesfdc/) which turns salesforce.com API’s data model into ActiveRecords in a similar way as what you are trying to achieve here.
Any chance of seeing your model layer released open source ?
Cheers,
Rup
Thanks for the salesforce.com heads-up — they are doing some really neat SQL re-formatting in asf_adapter and are writing their data straight to the tables.
My source data is different enough that I couldn’t directly leverage their algorithm, but with sufficient time something functionally similar could be constructed.
To save time, I’m using ActiveRecord to save the data as well as read it: 37 Signals sends me an array of data for each entity that includes foreign keys and attributes. I turn these into an ActiveRecord compatible format, initialize my ActiveRecord::Base child with it and save it to the database.
Since the foreign keys (ex: person_id in timeentry) are labeled in accordance with ActiveRecord standards, I simply specify the foreign keys in the model and immediately have access to the associated objects.
Re: OSS
I’m of the opinion that basic interfaces like this should be maintained by the community so that the individual(s) can work on more rewarding problems — otherwise everyone wastes time creating the same interfaces and creating unique problems.
If there is enough interest I may set up a rubyforce project — if not, I’ll just shoot the individuals a copy of the model code when I’m done. =)
> I’m of the opinion that basic interfaces like this should be maintained by the community so that the individual(s) can work on more rewarding problems — otherwise everyone wastes time creating the same interfaces and creating unique problems.
Yeah, yeah, yeah. You’re the only person that requested it, but I’ll send you the model layer source. Pass me an email (posted in “about this project”) and I’ll mail back the archive.
I’m leaving the country (and going completely offline for 3 weeks) on Thursday, but if you send me questions before then there’s a distinct nonzero chance I’ll have time to respond. Not making promises… =)