Curiously Yes I can…
I was doing something similar with 2 contexts, Accounting and Social.
This one allows to create, update User
defmodule Chat.Accounting.User do
@moduledoc false
use Ecto.Schema
import Ecto.Changeset
alias __MODULE__
alias Chat.Accounting.Phone
schema "users" do
field :email, :string
field :name, :string
field :password, :string, virtual: true
field :password_hash, :string
has_one :phone, Phone, on_delete: :delete_all
timestamps()
end
@required_fields ~w(name email)a
@registration_fields ~w(password)a
@doc false
# Because of Postgres constraints errors
# You will receive only the first constraint error, not all of them!
def changeset(%User{} = user, attrs \\ %{}) do
user
|> cast(attrs, @required_fields)
|> validate_required(@required_fields)
|> validate_length(:name, min: 1, max: 32)
|> validate_format(:email, ~r/@/)
|> unique_constraint(:name, message: "Name already taken")
|> unique_constraint(:email, message: "Email already taken")
end
@doc false
def registration_changeset(user, attrs \\ %{}) do
user
|> changeset(attrs)
|> cast(attrs, @registration_fields)
|> validate_required(@registration_fields)
|> validate_length(:password, min: 6, max: 32)
|> generate_encrypted_password()
end
# PRIVATE
defp generate_encrypted_password(changeset) do
case changeset do
%Ecto.Changeset{valid?: true, changes: %{password: password}} ->
put_change(changeset, :password_hash, Comeonin.Bcrypt.hashpwsalt(password))
_ ->
changeset
end
end
end
This one allows to manage User association, inside Social context.
defmodule Chat.Social.User do
@moduledoc false
use Ecto.Schema
import Ecto.Changeset
alias __MODULE__
alias Chat.Social.{Group, Post, Comment}
schema "users" do
field :email, :string
field :name, :string
many_to_many :followeds, User,
join_through: "followings",
join_keys: [follower_id: :id, followed_id: :id],
on_delete: :delete_all,
on_replace: :delete
many_to_many :followers, User,
join_through: "followings",
join_keys: [followed_id: :id, follower_id: :id],
on_delete: :delete_all,
on_replace: :delete
many_to_many :groups, Group,
join_through: "subscriptions",
on_delete: :delete_all,
on_replace: :delete
has_many :owned_groups, Group
has_many :posts, Post
has_many :comments, Comment
timestamps()
end
def follow_changeset(%User{} = user, attrs \\ %{}) do
user
|> cast(attrs, [])
|> put_assoc(:followeds, attrs[:followeds])
end
def group_changeset(%User{} = user, attrs \\ %{}) do
user
|> cast(attrs, [])
|> put_assoc(:groups, attrs[:groups])
end
end
As You can see they refer to the same table, but they both represent a User, inside their respective contexts.
Social User cannot be created, they don’t know what a password is, but they can join group, and follow other User as well.