Both has_one and has_many pointing to the same schema

Hello everyone,

I’m looking for the correct way to declare a pair of schemas for a
document/revision system that would look something like this:

defmodule Document do
  use Ecto.Schema
  schema "documents" do
    field :created_by, :string
    has_many :revisions, DocumentRevision
    has_one :current_revision, DocumentRevision
  end
end

defmodule Document do
  use Ecto.Schema
  schema "documents_revisions" do
    field :revised_by, :string
    field :content, :string

    belongs_to :documents, Document
  end
end

where migration that defines the schema looks like the following

create table("documents") do
  add :created_by, :string
  add :current_revision_id, references(:document_revisions)
end

create table("document_revisions") do
  add :revised_by, :string
  add :content, :string
  add :document_id, references(:documents)
end

The immediate difficulty I’m having is updating the current_revision field.
I’m not sure what to pick for on_replace: option and updating current_revision_id
manually does not work either the following throws field latest_revision_id in update does not exist in schema Document in query when passed to update_all:

def set_revision(document, revision) do
  from(
    d in Document,
    where: d.id == ^document.id,
    update: [set: [current_revision_id: ^revision.id]]
  )

What would be a way to solve the above? The entities are not set in stone so if
there’s a better way to implement the general idea, I’m all ears as well.

This should be belongs_to :current_revision, DocumentRevision - the belongs_to always goes on the schema where the _id column is.

1 Like

Nice, thank you! Field reads a bit strange now, but this made it work :+1:

Yep, this kind of thing has been a headache since belongs_to and has_one (and surely for longer with different naming) :stuck_out_tongue:

This is from the initial commit to Rails in November 2004!

1 Like