Question

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.

Was it helpful?

Solution 2

My experience is that when you ask the question about making your own solution versus using a third-party solution the answer is almost always 'roll your own.' Not only can you make EXACTLY what you want in terms of functionality, you're not beholden to some other developer to:

  1. Fix their bugs
  2. Support the latest rails update/ruby update, etc.
  3. Not conflict in some way with your app in subtle ways you can't address (require different versions of dependent gems).

I say that if you have the ability you should spend the time and write exactly what you want. It will pay off big time two years from now.

OTHER TIPS

Use PaperTrail, and don't roll your own solution. I strongly disagree with Richard's answer. PaperTrail is a very active project, with many people contributing to bug fixes, supporting the latest Rails and Ruby versions, and handling gem conflicts.

If you don't like the way PaperTrail does something, you should fork it and change that behaviour. If it's a general improvement, submit a pull request so that we can all benefit from your work. Don't rewrite it from scratch, because you don't have the hindsight of bugs and edge-cases that the PaperTrail committers have already been through.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top