N.B. I don’t seem to have permission to post in the Phoenix section
Background
I’m learning Phoenix and my relational database skills are a bit rusty to say the least. I’m trying to create a data structure for creating musical chord progressions, whereby a Progression
has a many to many association with a Chord
. I’m loosely following this guide. To do this I have the following schema (please tell me if my design is generally awful by the way!):
# create_chords migration
defmodule Chordwitch.Repo.Migrations.CreateChords do
use Ecto.Migration
def change do
create table(:chords) do
add :numeral, :string
add :extension, :string
add :tonality, :string
add :function, :string
add :comments, :text
add :altered, :boolean, default: false, null: false
timestamps()
end
end
end
# lib/chords/chord.ex
defmodule Chordwitch.Chords.Chord do
use Ecto.Schema
import Ecto.Changeset
alias Progressions.Progression
schema "chords" do
field :altered, :boolean, default: false
field :comments, :string
field :extension, :string
field :function, :string
field :numeral, :string
field :tonality, Ecto.Enum, values: [:major, :minor, :neutral]
many_to_many :progressions, Progression, join_through: "progression_chords"
timestamps()
end
@doc false
def changeset(chord, attrs) do
chord
|> cast(attrs, [:numeral, :extension, :tonality, :function, :comments, :altered])
|> validate_required([:numeral, :extension, :tonality, :function, :comments, :altered])
end
end
# create_progressions migration
defmodule Chordwitch.Repo.Migrations.CreateProgressions do
use Ecto.Migration
def change do
create table(:progressions) do
add :name, :string
add :tags, {:array, :string}
timestamps()
end
end
end
# lib/progressions/progression.ex
defmodule Chordwitch.Progressions.Progression do
use Ecto.Schema
import Ecto.Changeset
alias Chords.Chord
schema "progressions" do
field :name, :string
field :tags, {:array, :string}
many_to_many :chords, Chord, join_through: "progression_chords"
timestamps()
end
@doc false
def changeset(progression, attrs) do
progression
|> cast(attrs, [:name, :tags])
|> validate_required([:name, :tags])
end
end
As you can see I’ve also created a relationship table for progression_chords
with many_to_many
associations in both my chord
and progression
schema. The migration for progression_chords
looks like this:
defmodule Chordwitch.Repo.Migrations.CreateProgressionChords do
use Ecto.Migration
def change do
create table(:progression_chords) do
add :progression_id, references(:progressions)
add :chord_id, references(:chords)
add :index, :integer
end
end
end
I’m trying to test this out by running my application in iex
and doing the following:
alias Chordwitch.Chords.Chord
Chordwitch.Chords.Chord
iex(2)> alias Chordwitch.Progressions.Progression
Chordwitch.Progressions.Progression
iex(3)> alias Chordwitch.Repo
Chordwitch.Repo
iex(4)> p = %Progression{name: "iex Rock"}
%Chordwitch.Progressions.Progression{
__meta__: #Ecto.Schema.Metadata<:built, "progressions">,
id: nil,
name: "iex Rock",
tags: nil,
chords: #Ecto.Association.NotLoaded<association :chords is not loaded>,
inserted_at: nil,
updated_at: nil
}
iex(5)> p = Repo.insert!(p)
Problem
When I run that last command and try and insert my progression (before building any associations), I get the following error:
** (UndefinedFunctionError) function Chords.Chord.__schema__/1 is undefined (module Chords.Chord is not available)
Chords.Chord.__schema__(:primary_key)
(ecto 3.10.1) lib/ecto/changeset/relation.ex:155: Ecto.Changeset.Relation.change/3
(ecto 3.10.1) lib/ecto/changeset/relation.ex:526: anonymous fn/4 in Ecto.Changeset.Relation.surface_changes/3
(elixir 1.14.4) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto 3.10.1) lib/ecto/changeset/relation.ex:513: Ecto.Changeset.Relation.surface_changes/3
(ecto 3.10.1) lib/ecto/repo/schema.ex:344: Ecto.Repo.Schema.do_insert/4
(ecto 3.10.1) lib/ecto/repo/schema.ex:273: Ecto.Repo.Schema.insert!/4
This error is the reason I have alias
ed Chord
in the Progression
module and vice versa, it’s not something that was in the guide.
Sorry for the long post but any pointers would be appreciated.