RyanB
RyanB

Reputation: 707

Rails & Papertrail - Include previous version in query

I'm creating an application the requires Admin approval when articles are created and updated. I used paper trail to accomplish this, storing each update to the articles.

When an article is updated, the "published" field is set to false. Since I want to display the most recent Approved/Published version of the article, I need a sort of scope that checks if the current version of the article is approved, and if it is not, it searches back through previous versions until it finds an approved/published one.

def self.published(query={})
  where(query).map do |article|
    article.published? ? article : article.last_published_version
  end.compact! || []
end

def published?()
  published
end

def last_published_version()
  return self if published?
  published_versions = versions.select{ |version| version.reify.try(:published?) } 
  published_versions.present? ? published_versions.last.reify : nil
end

Now, since I am using map here, my query is returning an array instead of a ActiveRecord Relation. I would like to chain additional queries on the published articles, so this is a problem.

For example, I would like to do: Article.published.where(...).order_by(...), etc

Any ideas on accomplishing this?

Upvotes: 2

Views: 2526

Answers (2)

hrdwdmrbl
hrdwdmrbl

Reputation: 5279

If you add a has_many :versions, as: :item, class_name: 'PaperTrail::Version' to your model, then you can use include(:versions). However, this won't eager query for all PaperTrail queries such as version_at because that query includes a created_at scope. What you can do instead of using the version_at method is something like Foo.includes(:versions).first.versions.find { |f| f.created_at > date }. This is suggested in PaperTrail's issues here.

Me wanting to include(:versions) for multiple Foo, I did a separate query for versions after querying for Foo

    foo_versions = PaperTrail::Version.where(
      item_type: 'Publication',
      item_id: foos.map(&:id),
    ).where("created_at >= ?", date).order(:created_at)

and then I built a lookup index

    foo_index = foo_versions.each_with_object({}) do |foo, mapping|
      mapping[foo.item_id] ||= foo
    end

This allowed me to omit a n+1 query situation.

Upvotes: 0

nowk
nowk

Reputation: 33171

I'd suggest making a direct association and joins the 2 together so you can add search terms against the versioning table. I would also use a custom version class (not that you can't do this with the default version table) and set the meta data you would regularly access (or need to access for the search), as the version is serialized, through their meta option. Would probably be faster and searching/accessing data would be more convenient this way.

Upvotes: 1

Related Questions