Skip to content

Instantly share code, notes, and snippets.

@jwaldrip
Last active April 8, 2018 20:59
Show Gist options
  • Save jwaldrip/03a5f3923387a7a3245a474a38f89985 to your computer and use it in GitHub Desktop.
Save jwaldrip/03a5f3923387a7a3245a474a38f89985 to your computer and use it in GitHub Desktop.
api_1 | Request: POST /graphql
api_1 | ** (exit) an exception was raised:
api_1 | ** (Ecto.ConstraintError) constraint error when attempting to insert struct:
api_1 |
api_1 | * unique: user_emails_address_index
api_1 |
api_1 | If you would like to convert this constraint into an error, please
api_1 | call unique_constraint/3 in your changeset and define the proper
api_1 | constraint name. The changeset has not defined any constraint.
api_1 |
api_1 | (ecto) lib/ecto/repo/schema.ex:574: anonymous fn/4 in Ecto.Repo.Schema.constraints_to_errors/3
api_1 | (elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
api_1 | (ecto) lib/ecto/repo/schema.ex:559: Ecto.Repo.Schema.constraints_to_errors/3
api_1 | (ecto) lib/ecto/repo/schema.ex:222: anonymous fn/14 in Ecto.Repo.Schema.do_insert/4
api_1 | (ecto) lib/ecto/association.ex:556: Ecto.Association.Has.on_repo_change/4
api_1 | (ecto) lib/ecto/association.ex:338: anonymous fn/7 in Ecto.Association.on_repo_change/6
api_1 | (elixir) lib/enum.ex:1899: Enum."-reduce/3-lists^foldl/2-0-"/3
api_1 | (ecto) lib/ecto/association.ex:335: Ecto.Association.on_repo_change/6
api_1 | (elixir) lib/enum.ex:1899: Enum."-reduce/3-lists^foldl/2-0-"/3
api_1 | (ecto) lib/ecto/association.ex:301: Ecto.Association.on_repo_change/3
api_1 | (ecto) lib/ecto/repo/schema.ex:708: Ecto.Repo.Schema.process_children/4
api_1 | (ecto) lib/ecto/repo/schema.ex:774: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
api_1 | (ecto) lib/ecto/adapters/sql.ex:576: anonymous fn/3 in Ecto.Adapters.SQL.do_transaction/3
api_1 | (db_connection) lib/db_connection.ex:1283: DBConnection.transaction_run/4
api_1 | (db_connection) lib/db_connection.ex:1207: DBConnection.run_begin/3
api_1 | (db_connection) lib/db_connection.ex:798: DBConnection.transaction/3
api_1 | (ecto) lib/ecto/repo/schema.ex:125: Ecto.Repo.Schema.insert!/4
api_1 | (gigsmart) lib/gigsmart_graphql/mutation/user.ex:23: anonymous fn/2 in GigSmartGraphQL.Mutation.User.__absinthe_type__/1
api_1 | (absinthe) lib/absinthe/resolution.ex:206: Absinthe.Resolution.call/2
api_1 | (absinthe) lib/absinthe/phase/document/execution/resolution.ex:209: Absinthe.Phase.Document.Execution.Resolution.reduce_resolution/1
defmodule GigSmart.Context.User do
import Ecto.Query
alias GigSmart.{Repo, Model}
alias Model.{User, UserEmail}
def all do
Repo.all(User)
end
def get(id) do
Repo.get(User, id)
end
def create(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
|> User.require_email_address()
|> Repo.insert!(returning: true)
end
end
defmodule GigSmart.Model.UserEmail do
use Ecto.Schema
import Ecto.Changeset
alias GigSmart.Model.User
@primary_key {:id, Ecto.UUID, autogenerate: true}
@foreign_key_type Ecto.UUID
schema "user_emails" do
field(:address, :string)
field(:confirmed, :boolean)
timestamps()
belongs_to(:user, User)
end
@permitted_attrs ~w{address}a
@required_attrs ~w{address}a
@doc false
def changeset(%__MODULE__{} = email, attrs \\ %{}) do
email
|> cast(attrs, @permitted_attrs)
|> validate_required(@required_attrs)
|> unique_constraint(:address)
end
end
defmodule GigSmart.Model.User do
use Ecto.Schema
import Ecto.Changeset
alias GigSmart.Model.{Worker, Requester, UserEmail}
alias Comeonin.Bcrypt, as: HashAlgo
@primary_key {:id, Ecto.UUID, autogenerate: true}
@foreign_key_type Ecto.UUID
schema "users" do
field(:email_address, :string, virtual: true)
field(:password, :string, virtual: true)
field(:password_confirmation, :string, virtual: true)
field(:password_hash, :string)
field(:first_name, :string)
field(:last_name, :string)
field(:mobile_number, :string)
field(:birthdate, :date)
field(:profile_photo_url, :string)
timestamps()
has_one(:worker, Worker)
has_one(:individual_requester, Requester, foreign_key: :individual_user_id)
has_many(:emails, UserEmail)
end
@permitted_attrs ~w{email_address password first_name last_name mobile_number birthdate profile_photo_url}a
@required_attrs ~w{password_hash}a
@doc false
def changeset(%__MODULE__{} = user, attrs \\ %{}) do
user
|> cast(attrs, @permitted_attrs)
|> put_password_hash
|> validate_required(@required_attrs)
end
def require_email_address(changeset) do
%Ecto.Changeset{changes: %{email_address: email_address}} = changeset
changeset
|> change(%{email_address: nil, emails: [%{address: email_address}]})
|> cast_assoc(:emails, required: true)
end
def authenticate(%__MODULE__{} = user, password) do
HashAlgo.check_pass(user, password)
end
defp put_password_hash(changeset) do
case changeset do
%Ecto.Changeset{valid?: true, changes: %{password: password}} ->
changeset
|> validate_confirmation(:password)
|> validate_length(:password, min: 8)
|> change(HashAlgo.add_hash(password))
_ ->
changeset
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment