Maybe I can help by giving you an example of how things work:
User -> has_one -> Profile
Profile -> belongs_to -> User
Here are the schemas:
# schema/user.ex
defmodule Schema.User do
@moduledoc false
use Ecto.Schema
import Ecto.Changeset
@required_params [:email, :password]
schema "users" do
has_many :orders, Schema.Order
has_one :profile, Schema.User.Profile
field :email, :string
field :password, :string, virtual: true
field :encrypted_password, :string
timestamps()
end
def changeset(user, params \\ %{}) do
user
|> cast(params, @required_params)
|> cast_assoc(:profile)
|> validate_required(@required_params)
|> unique_constraint(:email, name: :unique_email)
|> validate_format(:email, ~r/\S+@\S+\.\S+/)
|> validate_length(:password, min: 6)
end
end
# schema/user/profile.ex
defmodule Schema.User.Profile do
@moduledoc false
use Ecto.Schema
import Ecto.Changeset
@required_params [:first_name, :last_name, :gender]
@optional_fields [:phone, :image]
schema "user_profile" do
belongs_to :user, Schema.User
field :first_name, :string
field :last_name, :string
field :gender, :string
field :phone, :string
field :image, :string
timestamps()
end
def changeset(profile, params \\ %{}) do
profile
|> cast(params, @required_params ++ @optional_fields)
|> validate_required(@required_params)
end
end
You can insert into database using changesets from schemas:
user_changeset = Schema.User.changeset(
%Schema.User{},
%{
:email => "contact@alexandrubagu.info",
:password => "123456"
}
)
profile_changeset = Schema.User.Profile.changeset(
%Schema.User.Profile{},
%{
:first_name => "Alexandru",
:last_name => "Bagu",
:gender => "male",
}
)
user_changeset = Schema.User.hash_password(user_changeset)
user_changeset = Ecto.Changeset.put_assoc(user_changeset, :profile, profile_changeset)
Persistence.Repo.insert(user_changeset)
In your controller you need to preload associations:
product = Persistence.Repo.get(Schema.User, 1) |> Persistence.Repo.preload(:profile)
or using Ecto.query:
def all do
query = from u in Schema.User,
join: p in assoc(p, :profile),
preload: [profile: p]
Persistence.Repo.all(query)
end
The following code is from controller:
defmodule Frontend.UserController do
def register(conn, %{"user" => params}) do
changeset = Schema.User.changeset(%Schema.User{}, params)
if changeset.valid? do
result = changeset
|> Schema.User.hash_password
|> Persistence.Repo.insert
case result do
{:ok, user} ->
conn
|> Guardian.Plug.sign_in(user)
|> redirect(to: page_path(conn, :index))
{:error, changeset} ->
conn
|> assign(:changeset, %{changeset | action: :insert})
|> render("register.html")
end
else
conn
|> assign(:changeset, %{changeset | action: :insert})
|> render("register.html")
end
end
end
If you want to use relationship in forms here is an example
<%= form_for @changeset, user_path(@conn, :register), fn f -> %>
<%= inputs_for f, :profile, fn fp -> %>
<div class="form-group">
<%= label fp, :gender, gettext "Gender" %>
<%= select fp, :gender, ["Mr": 1, "Mrs": 0], class: "form-control styled", id: "gender" %>
<%= error_tag fp, :gender %>
</div>
<div class="form-group">
<%= label fp, :first_name, gettext "First name" %>
<%= text_input fp, :first_name, class: "form-control" %>
<%= error_tag fp, :first_name %>
</div>
<div class="form-group">
<%= label fp, :last_name, gettext "Last name" %>
<%= text_input fp, :last_name, class: "form-control" %>
<%= error_tag fp, :last_name %>
</div>
<% end %>
<div class="form-group">
<%= label f, :email, gettext "Email" %>
<%= text_input f, :email, class: "form-control" %>
<%= error_tag f, :email %>
</div>
<div class="form-group">
<%= label f, :password, gettext "Password" %>
<%= password_input f, :password, class: "form-control" %>
<%= error_tag f, :password %>
</div>
<button type="submit" class="btn btn btn-primary"><%= gettext "Register" %></button>
<% end %>
I hope I give you an answer for your problem.