1

I have a Rails 3.2.14 app which has a Call model with many different associations. I want to be able to track changes to the Call model and somehow display a list of changes in the the Call Show View.

I've been reading about the audited gem which looks like it might do the trick. But before I dive into this I'm wondering the following.

How can I call audits from within the show view? I assume I can do something like passing a block:

<% @call.audits.each do |a| %> <%= a.action %> <%= a.audited_changes %> <% end %>

Will something like this work in the show view when I need to see changes made for a specific call?

How does the audited gem handle associations, especially has_many_through?

I'm looking to implement this feature soon but don't want to introduce any problems into my app. I assume installing in a development environment might be the best route first?

If anyone has experience with this gem or can help provide answers, I'd really appreciate it.

Update So I tried installing the audited gem and I was able to display the audit action and audited_changes. But the format of audited_changes is a serialized hash. How can I deserialize it and make the fields friendly? Also it appears that the gem does not record changes when using a has_many_through relationship/join table. So what I have now is a half-working audit gem with data that's not user friendly. Any way to pretty this up and make it meaningful to the user?

call.rb excerpt

 has_many :call_units
  has_many :units, through: :call_units
  belongs_to :nature
  belongs_to :service_level
  belongs_to :patient_sex
  belongs_to :insurance
  belongs_to :region
  has_many :call_special_equipments
  has_many :special_equipments, :through => :call_special_equipments
  belongs_to :transferred_from, :foreign_key => :transfer_from_id, :class_name => 'Facility'
  belongs_to :transferred_to, :foreign_key => :transfer_to_id, :class_name => 'Facility'
  belongs_to :parent_call, class_name: "Call"
  has_many :notes
  belongs_to :cancel_reason
nulltek
  • 3,247
  • 9
  • 44
  • 94
  • 1
    I see that your most recent edit is a year old, but have to ask: did you manage to display your audits in a readable manner? If not, I can help. – Tass Oct 28 '15 at 19:24
  • I know it's a long time now, but i can't seem to figure out how to display changes in an index page, i have `audited` added to the user model. – chrisgeeq Jul 27 '19 at 16:03

2 Answers2

1

I've used the paper_trail gem for auditing record changes Here is another SO answer that shows how to display the record deltas: Display all versions of individual records in Papertrail

No disparagement to the audited gem implied.

Community
  • 1
  • 1
scarver2
  • 7,887
  • 2
  • 53
  • 61
  • Can you expand on how you did this? Also including associated records and has many through relationships? – nulltek Oct 13 '14 at 21:10
  • What are some of the associations you are wanting to track with the `Call` model? Can you add the relevant source code to your question? – scarver2 Oct 13 '14 at 21:25
  • Sure, I'll post up an excerpt of my call model. – nulltek Oct 14 '14 at 12:11
  • I've posted up my associations from the `Call` model. I'm trying to track changes to polymorphic and `has_many_through` associations. Can you provide an answer on how to implement paper_trail to track changes? I'd really like to get this working. – nulltek Oct 14 '14 at 12:14
  • @cz3ch - I'm working on a similar issue and have deduced, after a bit of research, that there is not an off the shelf solution for tracking changes on the associated models in a way that makes the presentation of those changes meaningful to a user. I'm electing to write a custom class that will track changes to the associated models and store them in a Papertrail metadata column in the parent model. It seems the best solution, but happy to be put right if others have a better solution. – Betjamin Richards Oct 31 '14 at 10:14
  • @BetjaminRichards I am still working on this, but I ended up writing a custom class, model methods with call backs, and controller actions to make this work. Logging `has_many_through` has proved very challenging as no of the shelf solution logs this sort of association. Once I have it working, I'll post my code as an answer so you can get an idea of how I did it. It's a very complex method and should be abstracted into a gem but this solution is very "custom" to my app and may not apply to everyone else. Everything is stored in an Activities model using callbacks on the tracked model. – nulltek Oct 31 '14 at 13:59
1

We use something like this:

# app/views/audit_trail/index.html.haml
.table-responsive
  %table
    %thead
      %tr
        %th Record
        %th Associated With
        %th By
        %th Action
        %th Changes
        %th Version
        %th Remote Address
        %th Timestamp

    %tbody
      = render @audits

# app/views/audited/adapters/active_record/audits/_audit.html.haml
%tr
  %td
    = "#{audit.auditable_type}:"
    %br
    = "'#{audit.auditable.try(:audited_friendly)}'"
  %td= audit.associated.try(:audited_friendly)
  %td= audit.user.try(:name)
  %td= audit.action
  %td= audit.audited_changes
  %td= audit.version
  %td= audit.remote_address
  %td= audit.created_at

Note that audited_friendly is a method we've added to models that are audited. So for example, a User model returns the name attribute but a Pattern model returns the label attribute.

UPDATE

Here are the relevant controller methods for both objects with audits (User) and audit records for objects associated with a record (Client):

# app/controllers/audits_controller.rb
  def index
    load_user if params[:user_id]
    load_client if params[:client_id]

    @audits = find_audits
  end

  def load_user
    @auditable = User.find(params[:user_id])
  end

  def load_client
    @associated = Client.find(params[:client_id])
  end

  def find_audits
    if @auditable
      scope = @auditable.audits
    elsif @associated
      scope = Audited::Audit.where(associated_type: @associated.class.name, associated_id: @associated.id)
      scope = scope.where(auditable_type: params[:auditable_type]) if params[:auditable_type]
    end
    scope.reorder("id DESC, version DESC")
  end
jwadsack
  • 5,708
  • 2
  • 40
  • 50