Reputation: 707
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
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
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