PaperTrail and its versions

I’m building a Rails app and have added PaperTrail to add versioning support to one of my models. I have quite a strange use case for versioning though which isn’t normal.

For my application, a version is ONLY created as a result of a physical event happening. I have this all working and the versions are correctly made.

My problem is that on my models index page I wish to put a list of all the model instances including all the versions associated with it. I need these versions to be equally as important as the original model instances.

I can run Model.all which returns an ActiveRecord::Result . I can then return all versions associated with those model instances by running PaperTrail::Version.where(object: ‘model’). This too returns an ActiveRecord::Result but of the Versions. I can’t merge the two together as they are not the same type of thing. I have tried adding a method to my Model that loops through them all, checks if it has one or more versions and if it does then grabs each version and calls PaperTrails reify method to convert it back to a real instance of the model and adding it to an array. This would be fine but further on in my index action within my controller I need to chain extra ActiveRecord query commands such as order and joins. These do not work on an array.

Any ideas on how I can solve this dilemma?

Thanks,
Neil

What versions of Rails and PaperTrail? Also could we take a look at the actually code you have so far?

If I understand your question correctly, you are basically trying to list every record for a specific model and with that list every version for every returned record. Is that accurate?

I’m not terribly familiar with PaperTrail but I would probably store the records in a collection

def index
   models = Model.all
end

Then in the view do something like:

    <%- models.each do |model| %>
       <%= model.name %>
       <%= model.versions %>
    <%- end %>

You could even create a partial with the version data in a table if you wanted to extract info out of the main view.

<%- models.each do |model| %>
  <%= model.name %>
  <%= render 'models/versions', model: model %>
<%- end %> 

This code is 100% untested, 100% off-the-cuff, and I’m 100% sure I probably made some errors here. But I can’t be any more specific since you didn’t really provide any specific data and I’m hoping that this will at least give you an idea that may work, but no guarantees. :smile:

Hey,

Thanks for the reply. It’s the latest released versions of both Rails and PaperTrail. Unfortunatley I can’t use what you posted as I need to be able to chain further query commands onto it in order to sort or limit the returned results. I don’t have my code to hand but later this evening I will post some here for you to look over.

One method I thought of but rejected was to grabs all versions of the model, loop over them, reify (ie: turn them back into real instances of the model again) and add them to my Models table to store them, and at this point to run Model.all to get them all including the versioned ones and once grabbed, delete those records from the DB. This just seems like major overhead and i’d rather not go that route.

Neil

Are you trying to sort the records returned by the model or the versions returned by PaperTrail?

Also, could you create a dropdown/checkbox type solution that would filter the results within the actual page?

[quote=“scannon, post:4, topic:113200”]
Are you trying to sort the records returned by the model or the versions returned by PaperTrail?[/quote]

Both to be honest, but when they are all merged together. I need my Model AND it’s versions together so I can chain sorts and filtering queries onto the end.

[quote=“scannon, post:4, topic:113200”]
Also, could you create a dropdown/checkbox type solution that would filter the results within the actual page?[/quote]
My page DOES have links for filtering but the above is how I have built it so far.

Have a look at my controller code: (By the way my model is “Coaster”). It’s this block that confuses it:

  if params[:versions]
    # I need this route to return an ActiveRecord::Result of Coasters & their versions.
    @coasters = Coaster.including_versions
  else
    # If this route is taken I end up with an ActiveRecord::Result and can chain queries further on
    @coasters = Coaster.all
  end

   def index

      if params[:versions]
        @coasters = Coaster.including_versions
      else
        @coasters = Coaster.all
      end


      if params[:letters] || params[:type] || params[:misc] || params[:country]

         if params[:type]
            filter_by_type

            # Determine order based on whether 'letters' parameter is present
            if params[:letters]
               # Order by coaster name
               params[:sort] = 'alphabetically' unless params[:sort]
            else
               # Order by park name then coaster name
               params[:sort] = 'park' unless params[:sort]
            end
         end

         if params[:letters]
            filter_by_letters

            # Determine order based on whether 'type' parameter is present
            if params[:type]
               # Order by park name then coaster name
               params[:sort] = 'park' unless params[:sort]
            else
               # Order by coaster name
               params[:sort] = 'alphabetically' unless params[:sort]
            end
         end

         if params[:misc]
            filter_by_misc
         end

         if params[:country]
            filter_by_country
         end

      end

      if params[:sort] == 'order'
         @coasters = @coasters.except(:order).order('coasters.order_ridden ASC')
      elsif params[:sort] == 'park'
         @coasters = @coasters.joins(:park).order('parks.name ASC').order('coasters.name ASC')
      elsif params[:sort] == 'alphabetically'
         @coasters = @coasters.except(:order).order('coasters.name ASC')
      else
         @coasters = @coasters.joins(:park).order('coasters.name ASC').order('parks.name ASC')
      end

      @coasters = @coasters.page(params[:page] || 1).per(25)

      respond_to do |format|
         format.html

         format.js

         format.json do
          @coasters = Coaster(include: [:park, :manufacturer])
         end

         format.csv do
            @coasters = Coaster.all.includes(:park)
            render text: @coasters.to_csv
         end
      end
   end

I have tried a couple of ways of writing the including_versions method. Both are shown below:

  def self.including_versions
    # Returns the correct type (ActievRecord::Result) but they are `Version`'s and not `Coaster`'s
    PaperTrail::Version.where(object: 'coaster')
  end

And

  def self.including_versions
   # This returns an Array of the right type of objects (as they've been reified) but as it's an array I can neither merge it with the @coasters variable nor chain queries onto it.
    coasters = []
    Coaster.all.each do |c|
      coasters << c
      if c.versions
        c.versions.each do |v|
          coasters << v.reify
        end
      end
    end
    coasters
  end

I hope this make some sense!

Thanks,
Neil

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.