May 20th, 2007
Well, I’ve been developing this plugin for a while now, and here it is! The use case I have for this is client side Rails applications that sometimes need to be offline.
The plugin allows one ‘master’ db to sync with unlimited ’slave’ databases. Records created/updated/deleted on the client will also be updated on the slave and vica versa. The only difference between the slave and master db’s is that the slave has a column for every syncable model called ‘real_id’ (if you don’t see the reason for this, read my last post on syncing).
So, for the slave:
- All syncable models must have a real_id attribute
- All syncable models must have ‘acts_as_syncable’ in them. You can specify attributes you want to sync by doing: act_as_syncable(:include => :extra_attribute, :except => :bad_attribute) # This takes the same arguments as to_xml
- You need someway of finding out when was the last sync (down) time. I do this by having a SyncLog model that records all the sync times and associates them with the current user.
For the master:
- You need a controller called syncs with two methods, up and down (example code in the README)
- You need to find out the last sync time for the client. It’s not enough doing this by user since a user may have multiple slaves under their name (so some would get out of sync). I do this by clients. When an rails app first syncs it creates a unique guid which it displays at log in. You can then find the client by guid, and when they last synched (or create a new time).
The code is very alpha and needs much more testing, so if you’ve any ideas or comments please post them below. There is one problem I’ve found. It goes like this:
- slave A does a ‘down’
- slave A updates an attribute of a record
- slave A does an ‘up’
- slave B then tries to update an attribute.
- slave B then does a ‘down’
- However, newer information is overwriting the editing that slave B has done.
How do we deal with it? FDS notifies the client and gets them to choose. Personally I use lock_versions and log a SyncError if it fails, letting the user choose afterwards….