Hex.pm Documentation

EctoIRS is an Elixir library that provides easy auditing capabilities for Ecto schemas and migrations. The library allows developers to automatically track who created or modified database records.

Features

  • 🔍 Automatic Audit Fields: Automatically add inserted_by and updated_by fields to your schemas
  • 🗃️ Migration Helpers: Easy-to-use migration functions for adding audit columns
  • ⚙️ Flexible Configuration: Customize field names, references, and behavior
  • 🚀 Auto-population: Support for automatic field population via MFA tuples
  • 📦 Zero Dependencies: Built on top of Ecto with minimal external dependencies

Installation

Add ecto_irs to your list of dependencies in mix.exs:

def deps do
  [
    {:ecto_irs, "~> 0.1.0"}
  ]
end

Quick Start

1. Add Audit Columns to Your Database

In your migration:

defmodule MyApp.Repo.Migrations.CreatePosts do
  use Ecto.Migration
  import EctoIRS.Migration

  def change do
    create table(:posts) do
      add :title, :string
      add :content, :text
      
      # Adds :inserted_by_id and :updated_by_id columns
      audits :users
      
      timestamps()
    end
  end
end

2. Add Audit Fields to Your Schema

In your schema:

defmodule MyApp.Post do
  use Ecto.Schema
  use EctoIRS.Schema

  schema "posts" do
    field :title, :string
    field :content, :text
    
    # Generates :inserted_by and :updated_by associations
    audits MyApp.User
    
    timestamps()
  end
end

3. Query with Audit Information

# Preload audit associations
post = MyApp.Repo.get(MyApp.Post, 1) |> MyApp.Repo.preload([:inserted_by, :updated_by])

# Access audit information
IO.puts "Created by: #{post.inserted_by.name}"
IO.puts "Last updated by: #{post.updated_by.name}"

Schema Usage

Basic Usage

defmodule MyApp.Post do
  use Ecto.Schema
  use EctoIRS.Schema

  schema "posts" do
    field :title, :string
    audits MyApp.User
    timestamps()
  end
end

Custom Field Names

defmodule MyApp.Post do
  use Ecto.Schema
  use EctoIRS.Schema

  schema "posts" do
    field :title, :string
    
    audits MyApp.User,
      inserted_by: :created_by,
      updated_by: :modified_by
  end
end

Disable Specific Fields

defmodule MyApp.Post do
  use Ecto.Schema
  use EctoIRS.Schema

  schema "posts" do
    field :title, :string
    
    # Only track who created, not who updated
    audits MyApp.User, updated_by: false
  end
end

Custom References

defmodule MyApp.Post do
  use Ecto.Schema
  use EctoIRS.Schema

  schema "posts" do
    field :title, :string
    
    audits MyApp.User, references: :user_id
  end
end

Automatic Field Population

defmodule MyApp.Post do
  use Ecto.Schema
  use EctoIRS.Schema

  schema "posts" do
    field :title, :string
    
    audits MyApp.User, autogenerate: {MyApp.Context, :current_user_id, []}
  end
end

Pre-configuration

defmodule MyApp.Post do
  use Ecto.Schema
  use EctoIRS.Schema

  @audits_opts [autogenerate: {MyApp.Context, :current_user_id, []}]

  schema "posts" do
    field :title, :string
    audits MyApp.User
  end
end

Migration Usage

Basic Migration

defmodule MyApp.Repo.Migrations.CreatePosts do
  use Ecto.Migration
  import EctoIRS.Migration

  def change do
    create table(:posts) do
      add :title, :string
      audits :users
      timestamps()
    end
  end
end

Custom Column Names

defmodule MyApp.Repo.Migrations.CreatePosts do
  use Ecto.Migration
  import EctoIRS.Migration

  def change do
    create table(:posts) do
      add :title, :string
      
      audits :users,
        inserted_by: :created_by,
        updated_by: :modified_by
      
      timestamps()
    end
  end
end

Nullable Columns

defmodule MyApp.Repo.Migrations.CreatePosts do
  use Ecto.Migration
  import EctoIRS.Migration

  def change do
    create table(:posts) do
      add :title, :string
      audits :users, null: true
      timestamps()
    end
  end
end

Adding to Existing Tables

defmodule MyApp.Repo.Migrations.AddAuditsToExistingTable do
  use Ecto.Migration
  import EctoIRS.Migration

  def change do
    alter table(:existing_posts) do
      audits :users
    end
  end
end

Custom Reference Options

defmodule MyApp.Repo.Migrations.CreatePosts do
  use Ecto.Migration
  import EctoIRS.Migration

  def change do
    create table(:posts) do
      add :title, :string
      
      audits :users,
        column: :user_id,
        on_delete: :nilify_all,
        on_update: :update_all
      
      timestamps()
    end
  end
end

Configuration

Repository Configuration

Configure default audit options at the repository level:

config :my_app, MyApp.Repo,
  migration_audits: [
    inserted_by: :created_by,
    updated_by: :modified_by,
    null: false
  ]

Schema Configuration Options

  • inserted_by: The field name for insertion audit (default: :inserted_by)
  • updated_by: The field name for update audit (default: :updated_by)
  • references: The field on the referenced table (default: :id)
  • autogenerate: MFA tuple for automatic field population

Migration Configuration Options

  • inserted_by: Column name prefix for insertion audit (default: :inserted_by)
  • updated_by: Column name prefix for update audit (default: :updated_by)
  • null: Whether columns accept null values (default: false)

Best Practices

1. Add Indexes for Performance

create index(:posts, [:inserted_by_id])
create index(:posts, [:updated_by_id])

2. Use Consistent Naming

Stick to either the default names or establish a consistent naming convention across your application.

3. Consider Nullable Columns

Decide whether audit fields should be required based on your application's security requirements.

4. Preload Associations

Always preload audit associations when you need to access the audit information:

posts = MyApp.Repo.all(MyApp.Post) |> MyApp.Repo.preload([:inserted_by, :updated_by])

Development

Running Tests

mix test

Code Quality

mix credo          # Run static code analysis
mix dialyzer       # Run type checking

Documentation

mix docs           # Generate documentation

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.