Repositories » Changeset Transactions & Associations

If you want to commit multiple changesets, it's a good idea to wrap that operation in a repository transaction. Changesets can be associated with each other using Changeset#associate method, which will automatically set foreign keys for you, based on schema associations.

Let's define :users relation that has many :tasks:

require 'rom'

rom = ROM.container(:sql, 'sqlite::memory') do |conf|
  conf.default.create_table(:users) do
    primary_key :id
    column :name, String, null: false
  end

  conf.default.create_table(:tasks) do
    primary_key :id
    foreign_key :user_id, :users, null: false
    column :title, String, null: false
  end

  conf.relation(:users) do
    schema(infer: true) do
      associations do
        has_many :tasks
      end
    end
  end

  conf.relation(:tasks) do
    schema(infer: true) do
      associations do
        belongs_to :user
      end
    end
  end
end

With associations established in the schema, we can easily associate data using changesets and commit them in a transaction:

class UserRepo < ROM::Repository[:users]
  commands :create
end

class TaskRepo < ROM::Repository[:tasks]
  commands :create
end

task_repo = TaskRepo.new(rom)
user_repo = UserRepo.new(rom)

task = task_repo.transaction do
  user = user_repo.create(name: 'Jane')

  new_task = task_repo.changeset(title: 'Task One').associate(user)

  task_repo.create(new_task)
end

task
# #<ROM::Struct[Task] id=1 user_id=1 title="Task One">

Association name

Notice that associate method can accept a rom struct and it will try to infer association name from it. If this fails because you have an aliased association then pass association name explicitly as the second argument, ie: associate(user, :author)

Learn more