My question: Should I roll my own model versioning or use one of the versioning gems that's already out there? If I should use a gem, which one seems best for this application?
Info about my app
My app is a simple Checklist app. There are Checklists and Jobs, and I track user responses with Responses and Submissions. The Response tells me what the use said ("Done", with a note "We need more mops.") and the Submission tells me when that particular Checklist was filled out (because there may be many submissions and sets of responses for a given checklist). I'll show my associations below, in case that helps.
#checklist.rb
class Checklist < ActiveRecord::Base
has_many :jobs, :through => :checklists_jobs
has_many :submissions
end
#job.rb
class Job < ActiveRecord::Base
has_many :checklists, :through => :checklists_jobs
has_many :responses
end
#response.rb
class Response < ActiveRecord::Base
belongs_to :job
belongs_to :submission
belongs_to :user
end
#submission.rb
class Submission < ActiveRecord::Base
belongs_to :user
belongs_to :checklist
has_many :responses
end
What I'm trying to do with versioning
What I want to do is record users' responses to jobs on checklists. But I want to make sure that I can reproduce the original checklist (with response information) if the checklist changes. For example, I want to make sure I can answer this question for all previous versions of a checklist:
"What did the checklist look like, and what were the responses three Tuesdays ago?"
I don't want to lose the answer to that question if I change the checklist or any of its jobs.
I think the best way to do this is to use versioning (for jobs and checklists). For example, if a Job is changed (the name or description) by an admin, then I don't update the existing job, but create a new version and leave the old version intact. Then I just leave the old stuff in place and point the checklist to the new version of the job.
Should I use a gem or roll my own?
What I'm trying to decide is whether I should just roll my own (write code to increment the version, point everything to the version, and preserve the previous version) or use an existing solution. The two best solutions seem to be paper_trail and vestal_versions. I don't have enough reputation points to post more than two links, so I'll link to each of gem's Railscast (which will get you to the gem itself if you want). Railscast 255 Undo with paper_trail and Railscast 177 Model Versioning - 177 uses vestal_versions.
Pros to rolling my own:
- I need to report on all historical data by reconstructing checklists and their responses. This is a main feature of the app. It seems like this will be tricky with the gems I mentioned.
- I'll be able to report on groups of versions ("I want to see all responses for any version of this Job"). That seems easy this way.
Cons to rolling my own:
- It's going to be tricky because I have several has_many :through associations. I'll have to be really careful to update all the tables and join tables correctly. (This may also be an issue with one of the gems).
- Since I'm using this version data for reporting, I'm concerned about performance issues. Parsing hashes seems computationally expensive, whereas relying on flat tables with indexes seems pretty efficient.
- Both gems seem more geared to keeping version history for tracking, and not really for maintaining historical information for reporting purposes.
This seems important because whatever I decide I'll basically be stuck with. I don't think it will be easy to switch from one method to another later.