Aujourd’hui je vais vous présenter une gem permettant de garder une trace des actions réalisées dans une application Rails de manière simple. Cette gem se nomme Audited et permet d’historiser les modifications sur nos modèles Rails avec seulement quelques lignes de code.
De plus elle permet de consulter les données enregistrées par le biais de méthodes utilisables directement sur les modèles, et laisse quelques libertés de configuration afin d’affiner les informations ainsi sauvegardées.
Installez la gem :
# Gemfile
gem "audited", "~> 4.5"
$ rails generate audited:install
$ rake db:migrate
Ceci va générer une migration et créer une table audits
.
C’est à partir de maintenant que l’on fait le choix des informations que l’on veut enregistrer.
Pour commencer, enregistrer toutes les actions effectuées sur un modèle est aussi simple que d’ajouter l’instruction audited
sur celui-ci.
À cela s’ajoute des options permettant de restreindre le scope d’enregistrement, ainsi que l’ajout d’informations :
audited only: []
, audited except: []
offrent la possibilité de restreindre le déclenchement de l’enregistrement seulement si certains attributs sont modifiés ;audited on: []
limite les actions déclenchant un enregistrement.Pour compléter les informations enregistrées, par exemple pour donner des précisions sur le contexte, il est possible d’ajouter des commentaires :
@product.update_attributes(
quantity: 3,
audit_comment: "Changement depuis le compte client"
)
Dans le même genre, si l’on veut conserver les informations d’un modèle associé au moment de l’action :
class Product < ActiveRecord::Base
belongs_to :category
audited associated_with: :category
class Category < ActiveRecord::Base
has_many :products
has_associated_audits
Pour ce qui est de l’auteur de l’action enregistrée, Audited utilise la méthode current_user
des contrôleurs.
Si elle n’existe pas, il faudra donc soit l’ajouter, soit préciser à Audited quelle méthode utiliser :
# config/initializers/autdited.rb
Audited.current_user_method = :authenticated_user
Pour accéder aux informations enregistrées, il est possible de les consulter au moyen de méthodes accessibles sur les modèles tagués audited
:
product = Product.create(quantity: 2)
product.update_attributes!(quantity: 3)
product.destroy
product.audits.count # => 3
# informations associées
category = Category.create(name: "Basket")
product = category.products.create(quantity: 3)
product.update_attribute(quantity: 2)
product.audits.last.associated # => #<Category name: "Basket">
company.associated_audits.last.auditable # => #<Product quantity: 2>
Audited assigne un numéro de version aux informations enregistrées. Il est donc possible d’accéder à une liste de versions, ou bien d’en consulter une grâce à son numéro ou en utilisant une date :
product.revisions
product.revision(1)
product.revision_at(Date.new(2017, 10, 17))
D’ailleurs voici la structure de base d’un enregistrement Audited :
<Audited::Audit
id: 1,
auditable_id: 16,
auditable_type: "Product",
associated_id: nil,
associated_type: nil,
user_id: 1,
user_type: "User",
username: nil,
action: "update",
audited_changes: {"description"=>["bla", "bla bla"]},
version: 1,
comment: nil,
remote_address: "0:0:0:0:0:0:0:1",
request_uuid: "744350ed-fb09-46c0-95ff-ecf883415e81",
created_at: "2017-10-09 14:32:13"
>
L’enregistrement est composé :
id
current_user
)Au fait, si l’on veut effectuer des actions sans que celles-ci soit enregistrées (sur un modèle sur lequel on veut normalement enregistrer les actions) ? … Eh bien c’est tout à fait possible :
@product.save_without_auditing
# La version block
@product.without_auditing do
@product.save
end
# Désactiver l'observation de colonnes
Product.non_audited_columns = [:quantity]
# Désactiver l'observation sur un modèle
product.auditing_enabled = false
On peut aussi passer directement par le modèle Audited::Audit
, qui est un modèle ActiveRecord
comme les autres.
À ce sujet, il est possible d’étendre ce modèle pour le personnaliser et y intégrer de nouvelles méthodes ou requêtes.
Pour cela, il faut créer un modèle héritant de la classe Audited::Audit
:
class CustomAudit < Audited::Audit
scope :custom_scope, -> { where() }
def custom_method
"Hey!"
end
end
Et initialiser Audited avec ce modèle personnalisé :
# config/initializers/audited.rb
Audited.config do |config|
config.audit_class = CustomAudit
end
Audited peut être utile à plusieurs fins :
git blame
, mais sur les donnéesIl faut tout de même veiller à la taille de la table audits
, qui peut rapidement faire un poids important si d’aventure on décidait d’enregistrer toutes les actions de l’application.
L’équipe Synbioz.
Libres d’être ensemble.
Nos conseils et ressources pour vos développements produit.