Elixir version: Elixir 1.4.2
Database: Postgres 9.6.1-2.pgdg80+1
Ecto version (mix deps):
* idna 4.0.0 (Hex package) (rebar3)
locked at 4.0.0 (idna) 10aaa9f7
ok
* inflex 1.8.0 (Hex package) (mix)
locked at 1.8.0 (inflex) 7cfc752a
ok
* mimerl 1.0.2 (Hex package) (rebar3)
locked at 1.0.2 (mimerl) 993f9b0e
ok
* connection 1.0.4 (Hex package) (mix)
locked at 1.0.4 (connection) a1cae722
ok
* metrics 1.0.1 (Hex package) (rebar3)
locked at 1.0.1 (metrics) 25f094de
ok
* fs 0.9.1 (Hex package) (rebar)
locked at 0.9.2 (fs) ed17036c
ok
* gettext 0.13.1 (Hex package) (mix)
locked at 0.13.1 (gettext) 5e0daf4e
ok
* ranch 1.3.2 (Hex package) (rebar3)
locked at 1.3.2 (ranch) e4965a14
ok
* poolboy 1.5.1 (Hex package) (rebar)
locked at 1.5.1 (poolboy) 6b461639
ok
* decimal 1.3.1 (Hex package) (mix)
locked at 1.3.1 (decimal) 157b3ced
ok
* poison 3.1.0 (Hex package) (mix)
locked at 3.1.0 (poison) d9eb6366
ok
* ssl_verify_fun 1.1.1 (Hex package) (rebar)
locked at 1.1.1 (ssl_verify_fun) 28a4d65b
ok
* scrivener 2.2.1 (Hex package) (mix)
locked at 2.2.1 (scrivener) 5a84cdfc
ok
* combine 0.9.6 (Hex package) (mix)
locked at 0.9.6 (combine) 8d1034a1
ok
* certifi 1.0.0 (Hex package) (rebar3)
locked at 1.0.0 (certifi) 1c787a85
ok
* hackney 1.7.1 (Hex package) (rebar3)
locked at 1.7.1 (hackney) e238c52c
ok
* tzdata 0.5.10 (Hex package) (mix)
locked at 0.5.10 (tzdata) 087e8dfe
ok
* timex 3.1.13 (Hex package) (mix)
locked at 3.1.13 (timex) 48b33162
ok
* db_connection 1.1.1 (Hex package) (mix)
locked at 1.1.1 (db_connection) f9d246e8
ok
* httpoison 0.11.1 (Hex package) (mix)
locked at 0.11.1 (httpoison) d06c5712
ok
* phoenix_pubsub 1.0.1 (Hex package) (mix)
locked at 1.0.1 (phoenix_pubsub) c10ddf62
ok
* oauth2 0.8.3 (Hex package) (mix)
locked at 0.8.3 (oauth2) 080ea0bf
ok
* cowlib 1.0.2 (Hex package) (rebar3)
locked at 1.0.2 (cowlib) 9d769a1d
ok
* cowboy 1.1.2 (Hex package) (rebar3)
locked at 1.1.2 (cowboy) 61ac29ea
ok
* mime 1.1.0 (Hex package) (mix)
locked at 1.1.0 (mime) 01c1d6f4
ok
* plug 1.3.0 (Hex package) (mix)
locked at 1.3.0 (plug) 6e2b01af
ok
* phoenix_html 2.9.3 (Hex package) (mix)
locked at 2.9.3 (phoenix_html) 1b5a2122
ok
* ja_serializer 0.12.0 (Hex package) (mix)
locked at 0.12.0 (ja_serializer) ba4ec5fc
ok
* ueberauth 0.4.0 (Hex package) (mix)
locked at 0.4.0 (ueberauth) bc72d5e5
ok
* ueberauth_facebook 0.6.0 (Hex package) (mix)
locked at 0.6.0 (ueberauth_facebook) 51006ed2
ok
* phoenix 1.2.1 (Hex package) (mix)
locked at 1.2.1 (phoenix) 6dc59224
ok
* phoenix_live_reload 1.0.8 (Hex package) (mix)
locked at 1.0.8 (phoenix_live_reload) 4333f9c7
ok
* postgrex 0.13.1 (Hex package) (mix)
locked at 0.13.1 (postgrex) ebf17b73
ok
* ecto 2.1.3 (Hex package) (mix)
locked at 2.1.3 (ecto) ffb24e15
ok
* timex_ecto 3.1.1 (Hex package) (mix)
locked at 3.1.1 (timex_ecto) 37d54f68
ok
* ecto_enum 1.0.1 (Hex package) (mix)
locked at 1.0.1 (ecto_enum) 7853cd36
ok
* scrivener_ecto 1.1.4 (Hex package) (mix)
locked at 1.1.4 (scrivener_ecto) 056aa1f3
ok
* straw_hat 0.0.1 (../straw_hat) (mix)
ok
* phoenix_ecto 3.2.2 (Hex package) (mix)
locked at 3.2.2 (phoenix_ecto) 2e51c576
ok
Migrations
create table(:users) do
# ...
end
create table(:identities) do
add :user_id, references(:users, on_delete: :delete_all), null: false
end
Schemas
defmodule UserSchema do
# ...
schema "users" do
has_many :identities, IdentitySchema, on_delete: :delete_all
end
end
defmodule IdentitySchema do
#...
@required_fields ~w(user_id)a
@optional_fields ~w()a
schema "identities" do
belongs_to :user, UserSchema
end
def changeset(model, params \\ %{}) do
model
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
|> assoc_constraint(:user)
end
end
Code
defp create_identity(user, auth) do
identity = Ecto.build_assoc(user, :identities)
IO.inspect(String.duplicate("*", 100))
IO.inspect(user)
IO.inspect(String.duplicate("-", 100))
IO.inspect(identity)
IO.inspect(String.duplicate("*", 100))
params = get_params_from_auth(auth)
changeset = IdentitySchema.changeset(identity, params)
case AppRepo.insert(changeset) do
{:error, reason} -> {:error, reason}
_ -> {:ok, user}
end
end
Output
"****************************************************************************************************"
%UserSchema{__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
id: 1,
identities: #Ecto.Association.NotLoaded<association :identities is not loaded>}
"----------------------------------------------------------------------------------------------------"
%{__meta__: #Ecto.Schema.Metadata<:built, "identities">,
__struct__: IdentitySchema,
id: nil,
user: #Ecto.Association.NotLoaded<association :user is not loaded>,
user_id: nil,
user_schema_id: 1}
"****************************************************************************************************"
Reason of failing
{:error,
#Ecto.Changeset<action: :insert,
changes: %{},
errors: [user_id: {"can't be blank", [validation: :required]}],
data: #IdentitySchema<>, valid?: false>}
The user_id should have the id from the user. For some reason it's under user_schema_id. Following the Ecto.build_assoc documentation.
iex> post = Repo.get(Post, 13)
%Post{id: 13}
iex> build_assoc(post, :comments)
%Comment{id: nil, post_id: 13}
The Comment have the post_id setup which is what I am expecting
This keep happening to me in other cases and I ended up just adding it manually, I always notice that [module_name]_id is actually the one that holds the value for some reason
Since ecto cannot rely on the association module accessible at compile-time (since that would create a cyclic dependency). Ecto tries to infer this on a bes-effort case using the related schema name as the base adding the _id suffix - you can provide the name explicitly with foreign_key option.
This is actually the same issue as https://github.com/elixir-ecto/ecto/issues/1948 (although in a different place), so I'm going to close this one and merge with the other.
@michalmuskala aaaaahhh I understand what you are doing.
@michalmuskala would you mind to tell me where this line https://github.com/elixir-ecto/ecto/blob/master/lib/ecto.ex#L465 jump to please? I can't follow the code 馃槩
@yordis the build functions per association defined on this module: https://github.com/elixir-ecto/ecto/blob/master/lib/ecto/association.ex
Most helpful comment
Since ecto cannot rely on the association module accessible at compile-time (since that would create a cyclic dependency). Ecto tries to infer this on a bes-effort case using the related schema name as the base adding the
_idsuffix - you can provide the name explicitly withforeign_keyoption.This is actually the same issue as https://github.com/elixir-ecto/ecto/issues/1948 (although in a different place), so I'm going to close this one and merge with the other.