Auditedでモデル変更を監視しよう

[Audited](https://github.com/collectiveidea/audited)というGemを業務で利用するので、予習がてら触ってみました。

ドキュメントを翻訳したものに近い内容となっております。

- ドキュメントを読めるほど実力に自身がない人
- ライブラリを調べる際にいろんな記事を見て時間を消耗する人

上記の方々の助けとなれば幸いです。

# Auditedとは？

- RubyのGem(ライブラリ)
- モデルの変更を監視してくれるライブラリ

Auditedでは、「誰がその変更を行なったか」を記録したり、変更に対してコメントを付与することができます。
また、変更に関連したモデルを関連づけることも可能です。

※現在サポートされているORMは`ActiveRecord`のみとなります。`MongoMapper`をサポートしていたバージョンもありましたが、詳細は[ドキュメント](https://github.com/collectiveidea/audited)を参照ください。

# 前提

- Rails 5.2.2
- Ruby 2.5.4
- mysql2 0.5.2
- Audited 4.7.0

# 簡単なチュートリアル

まずはAuditedをインストール。Gemfileに以下を追記します。

```
gem "audited", "~> 4.7"
```

利用したいRailsアプリケーションのディレクトリで`audits`テーブルを作成しましょう。
モデル変更の監視データを置くためのテーブルです。

```
$ rails generate audited:install
$ rake db:migrate
```

ここまでで下準備は完了。
Auditedを反映させたいモデルに対して、下記のようなコードを追記します。

```ruby
class User < ActiveRecord::Base
  audited
end
```

上記の例では、`User`モデルに対してAuditedを反映させています。

デフォルトでは`User`モデルが`create`、`update`、`destroy`、された時、`Audits`テーブルに記録されます。

```ruby
user = User.create!(name: "Steve")
user.audits.count # => 1
user.update!(name: "Ryan")
user.audits.count # => 2
user.destroy
user.audits.count # => 3
```

また、`audits`テーブルは「どのactionが利用されたか」や「どのような変更がなされたか」の情報を持ちます。

```ruby
user.update!(name: "Ryan")
audit = user.audits.last
audit.action # => "update"
audit.audited_changes # => {"name"=>["Steve", "Ryan"]}
```

以前のバージョンのモデルを参照することも可能です。

```ruby
user.revisions
user.revision(1)
user.revision_at(Date.parse("2016-01-01"))
```


実際にどのように監視データがストックされているかは`audits`テーブルを参照するとわかりやすいです。
下記にカラムをまとめておきます。


|   　カラム名       |       解説         |
|:----------------:|:------------------|
| id               |                             |
| auditable_id     |監視先テーブルにおけるid          |
| auditable_type   |監視先のモデル名                |
| associated_id    |関連モデルのid                 |
| associated_type  |関連モデル名                   |
| user_id          |変更を加えたUserのid            |
| user_type        |変更を加えたUser属性(ex: Admin)|
| username         |                             |
| action           |変更時のアクション名(ex: action)    |
| audited_changes  |変更内容                       |
| version          |変更回数                       |
| comment          |コメント                         |
| remote_address   |操作を行なったユーザーのIPアドレス   |
| request_uuid     |リクエスト時のuuid                 |
| created_at       |                              |


# 利用Tips

## 特定のカラム・アクションのみ監視を行う

デフォルトでは監視先の全てのカラムに対し、`create`、`update`、`destroy`アクションが行われた場合、`audits`テーブルに記録します。
しかし、特定のカラム・アクションに対してのみ、監視を行うようにすることも可能です。

```ruby
class User < ActiveRecord::Base
  # 全てのカラム・アクションを監視
  audited

  # nameカラムのみ監視
  audited only: :name

  # nameカラムとaddressカラムを監視
  audited only: [:name, :address]

  # passwordカラム以外を監視
  audited except: :password

  # nameカラムのupdate, destroyアクションのみを監視
  audited only: :name, on: [:update, :destroy]
end
```

## モデルの変更に`comment`を残す

モデルを変更した際、上述のカラム一覧に記載されていた`comment`カラムにコメントを追加することができます。

どんな理由で変更を加えたのかが明記できて、便利ですね。

```ruby
user.update!(name: "Ryan", audit_comment: "Changing name, just because")
user.audits.last.comment # => "Changing name, just because"
```

コメントの追加を強制することも可能です。

```ruby
class User < ActiveRecord::Base
  audited :comment_required => true
end
```


## 監視データの保持数を制限する

無限に蓄積されていく監視データを制限することができます。

例えば、「`User`モデルの監視データは10コを超えないようにし、古いデータは削除していく」といったようなことが可能です。

```ruby:config/initializer/audited.rb
Audited.max_audits = 10 # 各モデルは最新10件まで保持する
```

特定にモデルのみに適用することも可能です。

```ruby
class User < ActiveRecord::Base
  audited max_audits: 10
end
```


## 関連モデルの監視

監視しているモデルで変更があった場合、そのモデルの親モデルも参照することが可能です。

```ruby
class User < ActiveRecord::Base
  belongs_to :company
  audited associated_with: :company
end

class Company < ActiveRecord::Base
  has_many :users
  has_associated_audits
end
```

上記のように記述することで、子モデルの`User`が変更された場合、関連モデルの`Company`を参照することができます。

```ruby
company = Company.create!(name: "Collective Idea")
user = company.users.create!(name: "Steve")
user.update!(name: "Steve Richert")
user.audits.last.associated # => #<Company name: "Collective Idea">
company.associated_audits.last.auditable # => #<User name: "Steve Richert">
```


# 終わりに

他にも細かいユースケースに対応しているので、気になる方はぜひ[ドキュメント](https://github.com/collectiveidea/audited)を見てみてください！