问题
This is a follow up question on Rails 4 x paper_trail: filter versions by item_id with nested resources.
—————
CONTEXT FROM PREVIOUS QUESTION
In my Rails 4 app, I have the following models:
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
end
class Post < ActiveRecord::Base
belongs_to :calendar
end
I installed the paper_trail gem to track changes on my post
model as explained in the documentation and it works like a charm.
Versions are displayed in the Calendars#Index
view, which serves as a dashboard to the user.
—————
Based on the answer to my previous question, I now have the following code in my CalendarsController
:
def index
@user = current_user
@calendars = @user.calendars.all
@comments = @user.calendar_comments.order("created_at DESC").limit(20)
@versions = PaperTrail::Version.where(item_id: Post.where(calendar_id: @calendars.ids)).order('id DESC').limit(10)
end
Problem is now: when a user destroys a post, all the versions associated with this post disappear.
What I would like instead, is to keep track of a post even after it is destroyed, including the version mentioning that it was destroyed.
How can I achieve that?
回答1:
The simplest way to achieve this is to use Paper Trail's metadata feature to store the appropriate users' ids on each post's version record. In other words, denormalise your data just a little to make querying easier.
class Post < ActiveRecord::Base
belongs_to :calendar
has_paper_trail meta: {user_id: :user_ids} # remember to add a user_id column to the versions table
def user_ids
calendar.user_ids # or whatever you need
end
end
Then you can do this in your CalendarsController
:
@versions = PaperTrail::Version.where(user_id: current_user.id)
.order('id DESC')
.limit(10)
回答2:
Instead of actually destroying a post, you could just mark it as destroyed and remove it from the scope. This will retain it's version history and allow you to restore a 'deleted' post if a mistake was made.
rails g migration AddDeletedToPosts deleted:boolean
If there's a point where you no longer need a post and it's version history, say after a period of time, you can create a garbage collector for permanent deletion or migration to a separate archive.
Clarification
A version only belongs to the object it is tracking - in this case, a post. As such, when you destroy a post, you are effectively orphaning all of it’s versions. Yes, they do exist in the database and are present in a query of all versions, but you can no longer scope them because they aren’t related to anything. This is why I suggested virtually destroying posts until you no longer care about it’s version history. Does that make any sense?
来源:https://stackoverflow.com/questions/33722350/rails-4-x-paper-trail-keep-track-of-versions-after-item-is-destroyed