Skip to content
Agentmart
Submit a tool

ecto-changeset-patterns

MANDATORY for ALL changeset work beyond basic CRUD.

Skill by igmarin

IndexedMIT★ 5
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/igmarin-ecto-changeset-patterns

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

MANDATORY for ALL changeset work beyond basic CRUD. Invoke before writing multiple changesets, cast_assoc, or conditional validation. Covers separate changesets per operation, cast_assoc pitfalls, composition, conditional validation with opts, field transformations, and uniqueness validation. Trigger words: changeset, cast_assoc, validation, separate changesets, conditional validation, update_change.

Use cases: writing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/ecto-changeset-patterns

What's inside

Skill name
ecto-changeset-patterns
Description
MANDATORY for ALL changeset work beyond basic CRUD. Invoke before writing multiple changesets, cast_assoc, or conditional validation. Covers separate changesets per operation, cast_assoc pitfalls, composition, conditional validation with opts, field transformations, and uniqueness validation. Trigger words: changeset, cast_assoc, validation, separate changesets, conditional validation, update_change.
License
MIT
Metadata
version: 1.0.0 · user-invocable: true
Instructions
262 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# Ecto Changeset Patterns



## RULES — Follow these with no exceptions

**1.** **Define separate named changesets per operation** — `registration_changeset`, `email_changeset`, `password_changeset`, etc.
**2.** **Never require foreign key fields in `cast_assoc` child changesets** — `cast_assoc` sets them automatically
**3.** **Compose changesets with pipes** — each validation step is a separate, reusable function
**4.** **Always pair `unsafe_validate_unique` with `unique_constraint`** — fast UI feedback plus race-safe enforcement
**5.** **Use `update_change/3` for field transformations** — trim, downcase, and slugify inside the changeset
**6.** **Accept `opts \\ []` for conditional validation** — toggle hashing or uniqueness checks per call site
**7.** **Validate at the changeset level, not in context functions** — keep validation next to the schema


## FCIS at this boundary

Changeset functions should be pure data transformers (attrs in → changeset out). Persist with `Repo` in the context, not inside the schema module beyond optional helpers.

❌ **Bad:** schema function performs inserts

```elixir
def create(attrs) do
  %Post{}
  |> changeset(attrs)
  |> Repo.insert()
end
```

✅ **Good:** schema builds; context persists

```elixir
# schema
def changeset(post, attrs) do
  post
  |> cast(attrs, [:title, :body])
  |> validate_required([:title, :body])
end

# context shell
def create_post(attrs) do
  %Post{}
  |> Post.changeset(attrs)
  |> Repo.insert()
end
```

## Workflow: Building a New Schema

When adding changesets to a new schema, apply patterns in this order:

1. **Define separate named changesets** for each operation (registration, update, password change, etc.)
2. **Compose validations** into small, reusable private functions piped together
3. **Add uniqueness validation** — pair `unsafe_validate_unique` with `unique_constraint`
4. **Apply field transformations** via `update_change/3` in the changeset, not in controllers
5. **Verify** by testing in `iex -S mix` or running your changeset tests. A quick iex smoke test:

```elixir
# In iex -S mix
MyApp.Accounts.User.registration_changeset(%MyApp.Accounts.User{}, %{email: "bad", username: ""})
# => Inspect .valid? and .errors to confirm validations fire as expected

# Or a minimal ExUnit test
test "registration_changeset requires email and username" do
  changeset = User.registration_changeset(%User{}, %{})
  assert %{email: ["can't be blank"], username: ["can't be blank"]} = errors_on(changeset)
end
```


## Separate Changesets Per Operation

```elixir
defmodule MyApp.Accounts.User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :email, :string
    field :username, :string
    field :password, :string, virtual: true, redact: true
    field :hashed_password, :string, redact: true
    field :bio, :string

    timestamps()
  end

  # Registration — all fields, password hashing
  def registration_changeset(user, attrs, opts \\ []) do
    user
    |> cast(attrs, [:email, :username, :password])
    |> validate_email(opts)
    |> validate_username()
    |> validate_password(opts)
  end

  # Email change — only email
  def email_changeset(user, attrs, opts \\ []) do
    user
    |> cast(attrs, [:email])
    |> validate_email(opts)
  end

  # Password change — only password
  def password_changeset(user, attrs, opts \\ []) do
    user
    |> cast(attrs, [:password])
    |> validate_password(opts)
    |> put_password_hash()
  end

  # Profile update — non-sensitive fields only
  def profile_changeset(user, attrs) do
    user
    |> cast(attrs, [:username, :bio])
    |> validate_username()
  end
end
```

From igmarin/elixir-phoenix-skills, MIT.

More from igmarin/elixir-phoenix-skills

Signals

Stars
5
Forks
0
Open issues
0
Last commit (this folder)
Sep 28, 2026 (1 month ago)

From GitHub (fetched Oct 24, 2026).

Details

Version
1.0.0
License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from igmarin

Cite this page

ecto-changeset-patterns skill. Agent Mart. https://agentmart.dev/skills/igmarin-ecto-changeset-patterns (last updated 2026-10-24)