I’m making a notes app, and I don’t understand the following error:
warning: invalid association notes
in schema Swiftmemo.Accounts.User: associated schema SwiftMemo.Core.Note does not exist
lib/swiftmemo/accounts/user.ex:1: Swiftmemo.Accounts.User (module)
My User schema looks like this.
defmodule Swiftmemo.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias Swiftmemo.Accounts.User
schema "users" do
field :email, :string
field :provider, :string
field :token, :string
timestamps()
has_many :notes, Swiftmemo.Core.Note
end
end
If I alias the ‘Note’, the above error goes away:
defmodule Swiftmemo.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias Swiftmemo.Accounts.User
alias Swiftmemo.Core.Note # the alias that make the error go away.
schema "users" do
field :email, :string
field :provider, :string
field :token, :string
timestamps()
has_many :notes, Note
end
end
The “Note” looks like this:
defmodule Swiftmemo.Core.Note do
use Ecto.Schema
import Ecto.Changeset
alias Swiftmemo.Core.Note
schema "notes" do
field :body, :string
field :title, :string
timestamps()
belongs_to :user, Swiftmemo.Accounts.User
end
end
Is this expected behaviour?
Now that it compiles, I wasn’t getting the expected result in my ‘save’ function, and I started playing around in iex:
iex(1)> alias Swiftmemo.Core.Note
Swiftmemo.Core.Note
iex(2)> alias Swiftmemo.Accounts.User
Swiftmemo.Accounts.User
iex(3)> alias Swiftmemo.Repo
Swiftmemo.Repo
iex(4)> user = Repo.get(User, 1)
[debug] QUERY OK source="users" db=3.8ms queue=0.1ms
SELECT u0."id", u0."email", u0."provider", u0."token", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1) [1]
%Swiftmemo.Accounts.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
email: "-@-.com", id: 1,
inserted_at: ~N[2017-09-17 21:57:04.203340],
notes: #Ecto.Association.NotLoaded<association :notes is not loaded>,
provider: "github", token: "-",
updated_at: ~N[2017-09-17 21:57:04.207643]}
iex(5)> note1 = %{ "title" => "Test1", "body" => "This is test 1" }
%{"body" => "This is test 1", "title" => "Test1"}
iex(6)> note2 = %{ title: "Test2", body: "This is test 2" }
%{body: "This is test 2", title: "Test2"}
iex(7)> Ecto.build_assoc(user, :notes, note1)
%Swiftmemo.Core.Note{__meta__: #Ecto.Schema.Metadata<:built, "notes">,
body: nil, id: nil, inserted_at: nil, title: nil, updated_at: nil,
user: #Ecto.Association.NotLoaded<association :user is not loaded>, user_id: 1}
iex(8)> Ecto.build_assoc(user, :notes, note2)
%Swiftmemo.Core.Note{__meta__: #Ecto.Schema.Metadata<:built, "notes">,
body: "This is test 2", id: nil, inserted_at: nil, title: "Test2",
updated_at: nil,
user: #Ecto.Association.NotLoaded<association :user is not loaded>, user_id: 1}
With note 1, using a map, the title/body is not inserted into the resulting struct.
With note 2, using a keyword list, the title/body is inserted into the resulting struct.
According to the documentation "You can also pass the attributes, which can be a map or a keyword list, to set the struct’s fields except the association key.
"
I’m pretty confused, as the above is surprising behaviour to me.
Any hints as to what I am doing wrong would be greatly appreciated!
Thank you