Jmanda
Jmanda
AEAsh Elixir
Created by Jmanda on 4/20/2024 in #showcase
My proof of concept project (FleetMS) built with Ash
Not sure if it's fine to post here since its archived. I have been working on a personal project related to Fleet Maintenance and Management. Its a proof of concept, a learning thing, more like 40% complete. I have decided I will to rewrite it from scratch, it will be open source and will be building publicly. I hope from this I will learn a lot through collaboration, feedback e.t.c, and end up with something that can be used/adopted, or used as a reference for me and others and an awesome project I can put on my resume. In terms of licensing the only restriction I think I should put and is perhaps fair is preventing someone from taking the project and offering it as a SaaS(that's reserved for me), but they can sell it to individual clients. The end goal with regards to features is adding Fleet Telematics(companies love that very much), e.g third party integrations like Geotab, or streaming CAN Bus data from a vehicle with devices from CSSElectronics into the app, or build my own experimental vehicle tracking device, it could make a good IoT project using Nerves and all Elixir goodness πŸ˜€ . But first I need to get the "boring" stuff implemented first as you can see in the demo. So am asking from your thoughts on this. Here are credentials for the app(this won't running forever, I might turn it off on TuesdayπŸ˜€ ), and please for the sake of accessibility don't use it on your phone πŸ˜… link: https://fleetms.fly.dev email: [email protected] password: password1234
6 replies
AEAsh Elixir
Created by Jmanda on 4/30/2023 in #support
Implementating auto-incrementing/sequence fields in Ash Resources
I'm working on a project and I need to implement auto-incrementing fields, for example an Issue Number, Invoice Number, Service Number etc. I was thinking of creating a sequence table to keep track of multiple auto-increment field counts. issue_number counts, invoice_number counts, service_number counts, etc. I want to make sure that the implementation is consistent and that the sequence table will not leave gaps, as some database implementations leave gaps when a transaction fails. I want to hear your ideas on the best way to implement in Ash, and it would be cool if there was an extension for this, like AshSequenceπŸ˜„ Thank you in advance for your help!
3 replies
AEAsh Elixir
Created by Jmanda on 3/19/2023 in #support
** (KeyError) key :options not found: Error on AshPhoenix.Form submit
This is my form
<.simple_form
for={@form}
id="todo-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<div class="row">
<div class="col col-sm-12 col-md-6">
<.input field={@form[:title]} type="text" label="Title" />
</div>
</div>

<:actions>
<.button phx-disable-with="Saving...">
<i class="fa-solid fa-floppy-disk mr-2"></i>Save Todo
</.button>
</:actions>
</.simple_form>
<.simple_form
for={@form}
id="todo-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<div class="row">
<div class="col col-sm-12 col-md-6">
<.input field={@form[:title]} type="text" label="Title" />
</div>
</div>

<:actions>
<.button phx-disable-with="Saving...">
<i class="fa-solid fa-floppy-disk mr-2"></i>Save Todo
</.button>
</:actions>
</.simple_form>
In my FormComponent:
impl true
def update(%{todo: todo} = assigns, socket) do
form =
if todo do
AshPhoenix.Form.for_action(todo, :update,
as: "todo",
api: MyApp.Todos
)
else
AshPhoenix.Form.for_action(MyApp.Todos.Todo, :create,
as: "todo",
api: MyApp.Todos
)
end

{:ok,
socket
|> assign(assigns)
|> assign(:form, form |> to_form())}
end
impl true
def update(%{todo: todo} = assigns, socket) do
form =
if todo do
AshPhoenix.Form.for_action(todo, :update,
as: "todo",
api: MyApp.Todos
)
else
AshPhoenix.Form.for_action(MyApp.Todos.Todo, :create,
as: "todo",
api: MyApp.Todos
)
end

{:ok,
socket
|> assign(assigns)
|> assign(:form, form |> to_form())}
end
The form is rendering and validations are working fine, however on submiting the form am getting KeyError:
[error] GenServer #PID<0.1208.0> terminating
** (KeyError) key :options not found in: #AshPhoenix.Form<resource: MyApp.Todos.Todo, action: :create, type: :create, params: %{"title" => "asdf"}, source: #Ash.Changeset<action_type: :create, action: :create ...
...
[error] GenServer #PID<0.1208.0> terminating
** (KeyError) key :options not found in: #AshPhoenix.Form<resource: MyApp.Todos.Todo, action: :create, type: :create, params: %{"title" => "asdf"}, source: #Ash.Changeset<action_type: :create, action: :create ...
...
If I change the form to use :let:
<.simple_form
:let={f}
for={@form}
id="todo-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
....
<.simple_form
:let={f}
for={@form}
id="todo-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
....
and change the input field:
<div class="col col-sm-12 col-md-6">
<.input field={{f, :title}} type="text" label="Name" />
</div>
<div class="col col-sm-12 col-md-6">
<.input field={{f, :title}} type="text" label="Name" />
</div>
I get the following error:
key :title not found in: %{__changed__: nil, __given__: %{__changed__: nil, field: {%Phoenix.HTML.Form{source: #AshPhoenix.Form<resource: MyApp.Todos.Todo, action: :create ........
key :title not found in: %{__changed__: nil, __given__: %{__changed__: nil, field: {%Phoenix.HTML.Form{source: #AshPhoenix.Form<resource: MyApp.Todos.Todo, action: :create ........
What could be the issue? Is there something am missing?
9 replies
AEAsh Elixir
Created by Jmanda on 2/17/2023 in #support
Override/Extend AshAuthentication Sign in
On submitting user credentials, I want to do something(like a query on some resource) before user email and password validation, and if its successful I want put some stuff in the Process dictionary. How can I override/extend/hook-into the sign in actions in AshAuthentication? I know a can set stuff into the Process dictionary in the handle_success callback, but don't know where to put the other implementations. Thank you.
10 replies
AEAsh Elixir
Created by Jmanda on 2/8/2023 in #support
Create an Org on public schema and initial User on Org schema
I want to register an organization and an initial user at the same time. Creating an organizations automatically creates and apply migrations to the organization schema. The organization resource is global, so it's is saved on the public schema. The user should be saved on the organization schema. Steps(implementation in Ecto): 1. Generate a random string to be used as the organization schema name. 2. Create a schema with the random string as the schema name and apply migrations. 3. Create the organization on the public schema. 4. Create the user on the organization schema. 5. Save a user email and organization id to the "Lookup" table on the public schema. How can I implement this in Ash? Below is a similar implementation in Ecto: """
org_attrs = %{"name" => "My Org", "email" => "[email protected]"}

user_attrs = %{"email" => "[email protected]", "password" => "password123"}

schema_name = generate_random_string() # adb8469e0544

Ecto.Multi.new()
|> Ecto.Multi.run(:create_org, fn _repo, %{} ->
new_attrs =
org_attrs
|> Map.put("schema_name", schema_name)

MyApp.Accounts.create_organization(new_attrs)
end)
|> Ecto.Multi.run(:create_user, fn repo, %{create_org: org} ->
new_attrs =
user_attrs
|> Map.put("organization_id", org.id)

changeset = MyApp.Accounts.change_user(%MyApp.Accounts.User{}, new_attrs)
# Insert the user into the organization schema
repo.insert(changeset, prefix: org.schema_name)
end)
|> Ecto.Multi.run(:create_lookup, fn _repo, %{create_user: user, create_org: org} ->
new_attrs =
%{"email" => user.email, "organization_id" => org.id, "schema_name"=> org.schema_name}

MyApp.Accounts.create_lookup(new_attrs)
end)
org_attrs = %{"name" => "My Org", "email" => "[email protected]"}

user_attrs = %{"email" => "[email protected]", "password" => "password123"}

schema_name = generate_random_string() # adb8469e0544

Ecto.Multi.new()
|> Ecto.Multi.run(:create_org, fn _repo, %{} ->
new_attrs =
org_attrs
|> Map.put("schema_name", schema_name)

MyApp.Accounts.create_organization(new_attrs)
end)
|> Ecto.Multi.run(:create_user, fn repo, %{create_org: org} ->
new_attrs =
user_attrs
|> Map.put("organization_id", org.id)

changeset = MyApp.Accounts.change_user(%MyApp.Accounts.User{}, new_attrs)
# Insert the user into the organization schema
repo.insert(changeset, prefix: org.schema_name)
end)
|> Ecto.Multi.run(:create_lookup, fn _repo, %{create_user: user, create_org: org} ->
new_attrs =
%{"email" => user.email, "organization_id" => org.id, "schema_name"=> org.schema_name}

MyApp.Accounts.create_lookup(new_attrs)
end)
How can I implement this in Ash when using AshAuthentication? I find it easy to reason about implementation generated by phx.gen.auth but I'm not sure where I can plug in a custom implementation as shown above. Hope this makes sense. Thanks in advance.
22 replies
AEAsh Elixir
Created by Jmanda on 1/31/2023 in #support
Setting Tenant when using Context Multitenancy
So I have configure my resources to use context multitenancy (Postgres Schemas). Migrations are working fine and creating an org creates an org schema as well. My question is how can I set the tenant, assuming am getting the tenant from the subdomain, which can the be used in Ash queries? I have seen Ash.set_tenant/1 which takes a map as argument, what does the map look like? How is it different from Ash.Query.set_tenant/2? An also there what's called Process Context is Ash, what is it and assuming it's a data structure stored in the Process dictionary, how does it look like? Examples or pseudo code will help. Hopefully my questions are making sense 😁
23 replies