Thibaud Clement
Thibaud Clement

Reputation: 6897

Rails 4 x paper_trail: track which attributes are updated and display their new value

In my Rails 4 app, I am using paper_trail to track changes made by users on the records of the Post model:

# post.rb
has_paper_trail :on => [:update, :destroy]

A post belong_to a calendar and a calendar has_many post, so I display the changes made to posts in a dashboard located in the calendar index view:

<div id="my_changes">

  <% if @versions.any? %>

      <% @versions.each do |version| %>

      <% version.reify ? post = version.reify : post = Post.find_by_id(version.item_id) %>

      <p>
        <strong>
        <% if version.whodunnit.to_i === current_user.id %>
          You
        <% else %>
          <%= User.find_by_id(version.whodunnit).first_name %>
          <% end %>
        </strong> <%= conjugate(version.event) %> the post "<%= post.subject %>" in the <em><%= link_to Calendar.find_by_id(post.calendar_id).name, calendar_path(id: post.calendar_id) %></em> calendar <span id="update_time_ago">— <%= time_ago_in_words(version.created_at) %> ago.</span></p>

      <% end %>

  <% else %>

    <p>
      <span class="glyphicon glyphicon-hand-up" aria-hidden="true"></span><br/>There is no change to your posts yet.<br/>
      As soon as you update your calendar, a history of your changes will appear here.          
    </p>

  <% end %>

</div>

This is working fine.

What I would like to achieve now — and I can't figure out how — is not only to display which post has been updated, but also which attribute of the post has been updated and its value.

For instance, instead of:

User_1 updated the post "Test post" in the Test calendar — 3 days ago.

I would like to have something like:

User_1 updated the date / time / subject / copy / of the post "Test post" to NEW_POST_ATTRIBUTE_VALUE in the Test calendar — 3 days ago.

—————

UPDATE: I did read paper_trail's documentation, in particular the Choose attributes to monitor section, but this does seem to explain how to achieve what I am trying to achieve.

—————

UPDATE 2: I understand that what I am looking for may actually be explained in the Diffing versions section of the documentation.

So, I guess in my index.html.erb view, I could do something like:

post.versions.last.changeset

But then, how can I extract from there the information that I am interested in, eg: only the attribute that was updated, and its new value, and not the updated_at attribute, that I cannot ignore with paper_trail since I still want to know when the post was updated?

—————

UPDATE 3: in this Stack Overflow thread, @Maysam suggests:

With this behavior enabled, it is reasonably simple to get object.versions.map{|v| [v.created_at, v.changeset]} and then iterate over that structure to render your change log.

I am not sure I understand how I can actually iterate over that structure in my case: any suggestion?

—————

Can I actually achieve that with paper_trail?

Upvotes: 2

Views: 2806

Answers (1)

Jared Beck
Jared Beck

Reputation: 17528

.. I would like to .. display .. which attribute of the post has been updated and its value.

Per the documentation on Diffing Versions:

.. to diff adjacent versions .. add an object_changes text column to your versions table .. PaperTrail will store the changes diff .. in each update version. You can use the version.changeset method to retrieve it.

So, once you've done that, try adding

= debug post.versions.last.changeset

To your view. After that, if you know how to work with hashes in ruby, you should be good to go.

Upvotes: 2

Related Questions