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.
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.
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.
[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