Skip to content

Instantly share code, notes, and snippets.

@jeroenvisser101
Last active March 29, 2018 18:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeroenvisser101/ec661253874f20fa6de16505a22c9321 to your computer and use it in GitHub Desktop.
Save jeroenvisser101/ec661253874f20fa6de16505a22c9321 to your computer and use it in GitHub Desktop.
Elixir Issue because I'm a dumb shit.
defmodule Api.Accounts do
import Ecto.Query, warn: false
alias Api.Repo
alias Api.Accounts.Client
@doc """
Returns the list of clients.
## ISSUE
Preloading Users Here
"""
def list_clients do
Client
|> Repo.all()
|> Repo.preload(:users)
end
def get_client!(id), do: Repo.get!(Client, id)
def create_client(attrs \\ %{}) do
%Client{}
|> Client.changeset(attrs)
|> Repo.insert()
end
def update_client(%Client{} = client, attrs) do
client
|> Client.changeset(attrs)
|> Repo.update()
end
def delete_client(%Client{} = client) do
Repo.delete(client)
end
def change_client(%Client{} = client) do
Client.changeset(client, %{})
end
alias Api.Accounts.User
alias Api.Guardian
import Comeonin.Bcrypt, only: [checkpw: 2, dummy_checkpw: 0]
def token_sign_in(email, password) do
case email_password_auth(email, password) do
{:ok, user} ->
Guardian.encode_and_sign(user)
_ ->
{:error, :unauthorized}
end
end
defp email_password_auth(email, password) when is_binary(email) and is_binary(password) do
with {:ok, user} <- get_by_email(email),
do: verify_password(password, user)
end
defp get_by_email(email) when is_binary(email) do
case Repo.get_by(User, email: email) do
nil ->
dummy_checkpw()
{:error, "Login error."}
user ->
{:ok, user}
end
end
defp verify_password(password, %User{} = user) when is_binary(password) do
if checkpw(password, user.password_hash) do
{:ok, user}
else
{:error, :invalid_password}
end
end
def list_users do
Repo.all(User)
end
# List users by Client
def list_users_by_company(client_id) do
User
|> Ecto.Query.preload([:client])
|> where(client_id: ^client_id)
|> Repo.all()
end
def get_user!(id) do
User
|> Ecto.Query.preload([:client])
|> Repo.get!(id)
end
def create_user(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
|> Repo.insert()
end
def update_user(%User{} = user, attrs) do
user
|> User.changeset(attrs)
|> Repo.update()
end
def delete_user(%User{} = user) do
Repo.delete(user)
end
def change_user(%User{} = user) do
User.changeset(user, %{})
end
end
defmodule Api.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias Api.Accounts.User
import Comeonin.Bcrypt, only: [hashpwsalt: 1]
schema "users" do
field :first_name, :string
field :last_name, :string
field :email, :string
field :password_hash, :string
field :password, :string, virtual: true
field :password_confirmation, :string, virtual: true
belongs_to :client, Api.Accounts.Client
timestamps()
end
@doc false
def changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:first_name, :last_name, :email, :password, :password_confirmation, :client_id])
|> validate_required([:first_name, :last_name, :email, :password, :password_confirmation, :client_id])
|> validate_format(:email, ~r/@/)
|> validate_length(:password, min: 8)
|> validate_confirmation(:password)
|> unique_constraint(:email)
|> put_password_hash
end
defp put_password_hash(changeset) do
case changeset do
%Ecto.Changeset{valid?: true, changes: %{password: pass}}
->
put_change(changeset, :password_hash, hashpwsalt(pass))
_ ->
changeset
end
end
end
defmodule Api.Accounts.Client do
use Ecto.Schema
import Ecto.Changeset
schema "clients" do
field :company_name, :string
field :service, :string
field :country, :string
has_many :users, Api.Accounts.User
timestamps()
end
@doc false
def changeset(client, attrs) do
client
|> cast(attrs, [:company_name, :service, :country])
|> validate_required([:company_name, :service, :country])
end
end
defmodule ApiWeb.ClientController do
use ApiWeb, :controller
alias Api.Accounts
alias Api.Accounts.Client
action_fallback ApiWeb.FallbackController
def index(conn, _params) do
clients = Accounts.list_clients()
render(conn, "index.json", clients: clients)
end
def create(conn, %{"client" => client_params}) do
with {:ok, %Client{} = client} <- Accounts.create_client(client_params) do
conn
|> put_status(:created)
|> put_resp_header("location", client_path(conn, :show, client))
|> render("show.json", client: client)
end
end
def show(conn, %{"id" => id}) do
client = Accounts.get_client!(id)
render(conn, "show.json", client: client)
end
def update(conn, %{"id" => id, "client" => client_params}) do
client = Accounts.get_client!(id)
with {:ok, %Client{} = client} <- Accounts.update_client(client, client_params) do
render(conn, "show.json", client: client)
end
end
def delete(conn, %{"id" => id}) do
client = Accounts.get_client!(id)
with {:ok, %Client{}} <- Accounts.delete_client(client) do
send_resp(conn, :no_content, "")
end
end
end
defmodule ApiWeb.ClientView do
use ApiWeb, :view
alias ApiWeb.ClientView
def render("index.json", %{clients: clients}) do
%{data: render_many(clients, ClientView, "client.json")}
end
def render("show.json", %{client: client}) do
%{data: render_one(client, ClientView, "client.json")}
end
def render("client.json", %{client: client}) do
%{
id: client.id,
company_name: client.company_name
}
end
end
{
"data": [
{
"id": 1,
"company_name": "Brixtol Textiles"
},
{
"id": 2,
"company_name": "Sunday Seven"
}
]
}
{
"data": [
{
"id": 1,
"company_name": "Brixtol Textiles",
"users": [{
"last_name": "Savvidis",
"id": 1,
"first_name": "Nicos",
"email": "nicos@brixtol.com",
"client_id": 1
},{
"last_name": "Kjellander",
"id": 3,
"first_name": "Gustav",
"email": "gustav@sunday-seven.com",
"client_id": 2
}]
},
{
"id": 2,
"company_name": "Sunday Seven",
"users": [{
"last_name": "Savvidis",
"id": 1,
"first_name": "Nicos",
"email": "nicos@brixtol.com",
"client_id": 1
}]
}
]
}

Cannot seem to get desired response through relationship. Must be missing some step here. How does one return with the relationship?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment