defmodule MyApp.LineItem do use MyApp.Web, :model
schema "line_items" do field :variant, :string field :quantity, :integer field :price, :float field :options, :string
belongs_to :product, Product belongs_to :order, Order
timestamps # When the item is purchased from store. field :paid_at, Ecto.DateTime # When the item is shipped from store. field :shipped_at, Ecto.DateTime # When the item is delivered to origin endpoint. field :delivered_at, Ecto.DateTime end
@required_fields ~w(product_id variant quantity price) @optional_fields ~w(options paid_at shipped_at delivered_at)
@doc """ Creates a changeset based on the `model` and `params`.
If no params are provided, an invalid changeset is returned with no validation performed. """ def changeset(model, params \\ :empty) do model |> cast(params, @required_fields, @optional_fields) |> validate_inclusion(:quantity, 1..10) end
end
defmodule MyApp.Order do use MyApp.Web, :model alias MyApp.Order
schema "orders" do # Billing info, including name, phone, email, physical address. field :billing_address, :string # Shipping info, including name, phone, email, physical address. field :shipping_address, :string # Note from customer field :notes, :string # When customer pays for the order. field :paid_at, Ecto.DateTime # When the order is sent by courier. field :sent_at, Ecto.DateTime # When the order arrives at destination endpoint. field :arrived_at, Ecto.DateTime # When the order is shipped to customer. field :shipped_at, Ecto.DateTime # When the customer receives the order. field :delivered_at, Ecto.DateTime
# Generate inserted_at and updated_at. # These fields can determined the intial status of the order. # If inserted_at equals updated_at, the order is in cart. # Otherwise, the order is placed. timestamps
has_many :items, MyApp.LineItem, on_delete: :delete_all end
@required_fields ~w(billing_address shipping_address) @optional_fields ~w(notes paid_at sent_at arrived_at shipped_at delivered_at)
@doc """ Creates a changeset based on the `model` and `params`.
If no params are provided, an invalid changeset is returned with no validation performed. """ def changeset(model, params \\ :empty) do model |> cast(params, @required_fields, @optional_fields) # Ensure there are items in order. Delete old line items on replacing. |> cast_assoc(:items, required: true, on_replace: :delete) end
def all() do query = from order in Order, join: item in assoc(order, :items), join: product in assoc(item, :product), where: (order.updated_at != order.inserted_at) or not is_nil(item.id), preload: [items: {item, product: product}] Repo.all query end
def get!(id) do Repo.get!(Order, id) |> Repo.preload([items: [:product]]) endend
def update(conn, %{"id" => id, "order" => order_params}) do order = Order.get!(id) changeset = Order.changeset(order, order_params) case Repo.update(changeset) do {:ok, order} -> render(conn, "show.json", order: order) {:error, changeset} -> conn |> put_status(:unprocessable_entity) |> render(MyApp.ChangesetView, "error.json", changeset: changeset) end end
The items in the order are updated correctly, but since this update operation on the order is basically a no-op, why `updated_at` is touched?
Also, as a side question: my updated order does not load the `:product` association from inserted items. Is there a way to do that?
Also, as a side question: my updated order does not load the `:product` association from inserted items. Is there a way to do that?I am not sure I understood the question but is the answer possibly Repo.preload(order, :product)?