require_dependency 'chunk' class Revision < ActiveRecord::Base belongs_to :page belongs_to :web has_one :deconstructed, :dependent => true has_many :chunks, :dependent => true, :order => 'id ASC' validates_presence_of :author # utility to pick up the web affiliation from the page before_save :set_web def set_web() self.web ||= page.web end # after_save and not before as we need the chunks association collection to # exist. This is a two-stage save for the revisions: first the revision row # the the matching deconstructed content. Unfortunate, but I'd rather pre-cache # the deconstruction. after_save :deconstruct_markup PRE_ENGINE_ACTIONS = [ NoWikiChunk, IncludeChunk, SyntacticHighlightChunk, ExplicitLinkChunk, BlikiLinkChunk, InterWebLinkChunk, GlossaryDefinition ] POST_ENGINE_ACTIONS = [ GlossaryUsage, WikiWordChunk, TodoChunk ] # LiteralTagsChunk, LiteralPreChunk, URIChunk, def deconstruct_markup chunks.clear @display_content = nil @pre_render_cache = nil @pre_render_cache = markup_content.dup [PRE_ENGINE_ACTIONS, page.web.markup_engine, POST_ENGINE_ACTIONS].flatten.each do |chunk| @pre_render_cache.gsub! chunk.pattern do |matched_string| matched_bit = chunk.create :revision => self, :match_data => $~ matched_bit.mask_text end end chunks.reload if deconstructed deconstructed.content = @pre_render_cache deconstructed.save else deconstructed = Deconstructed.create :content => @pre_render_cache, :revision => self end end def display_content(view) chunks.reject do |chunk| chunk.is_a? MarkupEngine end.reverse.inject(deconstructed.content.dup) do |display_content, chunk| display_content.gsub chunk.mask_text, chunk.resolved_text(view) end end def pretty_created_at # Must use DateTime because Time doesn't support %e on at least some platforms DateTime.new( created_at.year, created_at.mon, created_at.day, created_at.hour, created_at.min ).strftime "%B %e, %Y %H:%M" end # Finds all the current revisions for a particular web. This is required for # the extra conditions processing, which can't be done wrom the Web has_many # relationship. def self.current_for(web, options={}) self.with_scope(:find => {:conditions => ['revisions.current = ? AND revisions.web_id = ?', true, web.id]}) do self.find(:all, options) end end # Should be called from within a transaction - see Page#revise def current! update_attribute :current, true Chunk.update_all ['current = ?', true], "revision_id = #{id}" end # Should be called from within a transaction - see Page#revise def not_current! update_attribute :current, false Chunk.update_all ['current = ?', false], "revision_id = #{id}" end end