| name | create-changeset |
| license | MIT |
| type | atomic |
| description | Creates a ROM changeset for write operations — creating, updating, or deleting data. Covers changeset types, input transformation, validation, and command composition. Use when implementing write operations for a repository. Trigger words: changeset, ROM changeset, create changeset, update changeset, ROM::Changeset, write operation, data mutation, command.
|
| metadata | {"version":"1.0.0","user-invocable":"true"} |
Creating a ROM Changeset
Define write rules for a relation. Every data mutation goes through a changeset — never call relation.insert directly.
Quick Reference
- Location:
slices/<slice>/changesets/
- Types:
ROM::Changeset::Create, ROM::Changeset::Update, ROM::Changeset::Delete.
- Usage:
repo.create(attrs) internally calls the changeset.
- Rule: Changesets validate and transform input. Repositories call them.
HARD-GATE
Changeset Constraints:
DO NOT call relation.command(:create).call(...) directly. Use a changeset.
DO NOT put business logic in changesets. Changesets validate and map input only.
Core Process
- Create the changeset for the target relation:
module Api
module Changesets
class CreateUser < ROM::Changeset::Create
map do |attrs|
attrs.merge(
created_at: Time.now,
status: "active"
)
end
def default_contract = UserContract.new
end
end
end
- Run the spec to verify changeset transforms input correctly before wiring into the repository:
bundle exec rspec spec/changesets/create_user_spec.rb
- Use in the repository — the repository's
create method delegates to the changeset:
class UserRepo < ROM::Repository[:users]
def create(attrs)
users.changeset(CreateUser, attrs).commit
end
end
- Update changeset — map input, merge timestamps, validate:
class UpdateUser < ROM::Changeset::Update
map do |attrs|
attrs.merge(updated_at: Time.now)
end
def allowed_keys = [:name, :email, :role]
end
- Compose changesets — chain multiple changesets with
.data for multi-step writes:
class UserRepo < ROM::Repository[:users]
def create_with_profile(user_attrs, profile_attrs)
user_cs = users.changeset(CreateUser, user_attrs)
profile_cs = profiles.changeset(CreateProfile, profile_attrs)
user_cs.data.then { |data| profile_cs.data.merge(owner_id: data[:id]) }
user_cs.commit
profile_cs.commit
end
end
Extended Resources (Progressive Disclosure)
Load these files only when needed:
Integration
| Skill | When to chain |
|---|
| define-relation | Define the relation schema before creating its changeset |
| create-repository | Use the changeset in the repository's write methods |
| create-operation | Operations call repositories which use changesets |