Reputation: 6897
I just installed the paper_trail
gem in my Rails 4 app.
So, now I have this in my schema.rb
:
create_table "versions", force: :cascade do |t|
t.string "item_type", null: false
t.integer "item_id", null: false
t.string "event", null: false
t.string "whodunnit"
t.text "object"
t.datetime "created_at"
end
I added paper_trail
to my Post
model:
class Post < ActiveRecord::Base
has_paper_trail
end
A post
has_many
comments
and belongs_to
a calendar
.
I am trying to display a history of recently modified posts in my Calendars#Index
view.
I used the official documentation and this tutorial for inspiration.
So, in calendars_controller.rb
, I have:
def index
@user = current_user
@calendars = @user.calendars.all
@comments = @user.calendar_comments.where.not(user_id: @user.id).order "created_at DESC"
@versions = PaperTrail::Version.order('id desc').limit(20)
end
And in my Calendar
index.html.erb
view, I have:
<h3 class="main_title">Updates</h3>
<div id="my_changes">
<% if @versions.any? %>
<table id="my_change_table">
<tr>
<th><span class="glyphicon glyphicon-calendar" aria-hidden="true"></span> CALENDAR </th>
<th><span class="glyphicon glyphicon-list" aria-hidden="true"></span> POST </th>
<th><span class="glyphicon glyphicon-user" aria-hidden="true"></span> AUTHOR </th>
<th><span class="glyphicon glyphicon-edit" aria-hidden="true"></span> CHANGE </th>
</tr>
<% @versions.each do |version| %>
<% post = Post.find_by_id(version.item_id) %>
<tr>
<td><%= Calendar.find_by_id(post.calendar_id).name %></td>
<td><%= post.subject %></td>
<td><%= User.find_by_id(version.whodunnit).first_name %></td>
<td><%= version.event.humanize + "d" %></td>
</tr>
<% end %>
</table>
<% else %>
<p>There was no change to your posts yet.</p>
<% end %>
</div>
This works actually pretty well when a user update
s a post.
However, as soon as a user destroy
s a post, I get the following error:
NoMethodError in Calendars#index
undefined method `item_id' for #<Post:0x007fff22e28c58>
<% post = Post.find_by_id(version.item_id) %>
In fact, this makes sense, since we destroy
ed the post
, it does not exist any more, so we can retrieve its id
.
But I thought this was precisely paper_trail
's job.
So, I must be missing something.
I tried to use the version.reify
and the version.previous
methods, but still ran into the same issue.
Any idea how to make this work?
Upvotes: 0
Views: 1098
Reputation: 10738
The problem is that after you destroy an object, reify will rerun a new instance of the object, which is unsaved and has no id.
Since it is deleted anyway you should expect Post.find_by_id(version.item_id)
to not find it anyway.
Edit
You should be able to get the properties of the original object from the version (see here)
So you can change your code to something like (assuming all of the versions in your system are calendars) and I think it should work:
<% @versions.each do |version| %>
<% post = version.reify %>
<tr>
<td><%= Calendar.find_by_id(post.calendar_id).name %></td>
<td><%= post.subject %></td>
<td><%= User.find_by_id(version.whodunnit).first_name %></td>
<td><%= version.event.humanize + "d" %></td>
</tr>
<% end %>
Upvotes: 1