I run a site similar to StackOverflow where users can publish content (Posts). There also is a frontpage showcasing featured Posts picked by our editors.
I want to allow our users to edit their Posts anytime, while still making sure nothing appears on our frontpage without it first being reviewed by our editors.
To solve this, I figured we could implement a versioning system like paper_trail and store the current version_id whenever we feature a Post. This way we can simply fetch the editor-reviewed content on the frontpage, while still showing the most recent version on less critical parts of the site such as the user's profile. Our editors can periodically review any changes and approve those.
I'm wondering what the cleanest approach is that allows me to select reviewed versions in some controllers and the latest versions in others while keeping a shared interface and minimally duplicated code.
The ideal solution would involve a reviewed scope so I could simply do Post.reviewed and get back the reviewed versions, and Post.all to get the latest versions.
I'm not sure how to go about this though, as getting the reviewed version requires de-serializing the object PaperTrail stores (version.reify) and that doesn't seem possible within a scope.
I could use a class method instead like this:
def self.reviewed
all.map do |post|
Version.find(post.version_id).reify
end.compact! || Post.none
end
However, this is less than ideal as it's not a real scope and thus not chainable, etc.
Alternatively I could use a Post instance method like:
def reviewed_version
Version.find(version_id).reify
end
This works in theory, but this means I now have to call this method all over my views, whereas it's the responsibility of the controller to fetch the right data. Let's say I have a render collection: @posts on both the frontpage and user profile, how does my _post.html.erb partial know whether to call reviewed_version or not.
I'm not tied to PaperTrail, but it has a lot of niceties I prefer not having to duplicate. I'm open to exploring other directions if PaperTrail proves too inflexible however.
FWIW, I have looked at Draftsman as well, but it considers the 'draft' as the exception (i.e. in most cases you wouldn't show the draft), whereas in my case I want to show the most recent version on most pages, except for a particular few like the frontpage.
This sounds over complicated for doing something that is quite simple by itself:
Postmodel, which contains common attributes (like author and creation date)Post has_many :revisionsRevisionhas areviewedboolean attributeIf you want to find the last reviewed revision for a
Post, you can have:if you want to retrieve only
Posts which have reviewed revisions:This is how I would have done it, let people more familiar with
paper_trailtell you about its way :)EDIT
As discussed in comments, a decorator may also help to differentiate the revision and delegate methods to it, while still being able to pass an activerecord relation. Which give something in that way: