【问题标题】:Phoenix 1.3 Using channel to insert dataPhoenix 1.3 使用通道插入数据
【发布时间】:2025-12-12 06:10:01
【问题描述】:

我正在尝试将我的应用程序从 phoenix 1.2 更新到 1.3。

在我的频道中,handle_in 函数之一获取 order_idfood_id 以创建 OrderItem

changeset = order
|> build_assoc(:order_items)
|> Myapp.OrderItem.changeset(%{food_id: food.id,
                              price: food.price,
                              quantity: 1, 
                              order_id: order.id,
                              created_date: time_now})

case Repo.insert(changeset) do
  {:ok, order_item} ->
    max_rounds = Repo.one!(from p in Myapp.OrderItem, where: p.order_id == ^order.id, select: max(p.round))
    Myapp.Order.changeset(order, %{total: order.total + (order_item.price * order_item.quantity), rounds: max_rounds}) |> Repo.insert_or_update
end

所以上面的代码来自phoenix 1.2版本的app,它的作用是当用户成功创建order_item时,它会更新order。它工作正常。

with {:ok, %OrderItem{} = order_item} <- Myapp.create_order_item(%{food_id: food.id,
                                                                        price: food.price,                                                                                                                              
                                                                        order_id: order.id,
                                                                        created_date: time_now}) do    

 max_rounds = Repo.one!(from p in OrderItem, where: p.restaurant_order_id == ^order.id, select: max(p.round))
 Myapp.update_order(order, %{total: order.total + (order_item.price * order_item.quantity), rounds: max_rounds})
end

Phoenix 1.3 引入了model 的新用法,所以我从Myapp 中调用create_order_item 函数来创建Myapp.OrderItemMyapp.OrderItem 来创建order_item

def create_order_item(attrs \\ %{}) do
 %OrderItem{}
 |> order_item_changeset(attrs)
 |> Repo.insert()
end

即使我将需要插入的所有字段都传递到数据库中,它也不会插入到数据库中。我应该如何解决它?我在这里做错了什么?

提前致谢。

---编辑

def create_order_item(attrs \\ %{}) do
 time_now = Ecto.DateTime.cast!
 (:calendar.universal_time_to_local_time(:calendar.universal_time()))
 %OrderItem{created_date: time_now}
 |> order_item_changeset(attrs)
 |> Repo.insert()
end

【问题讨论】:

  • 日志中是否有任何错误?还是整个代码运行没有错误但没有插入任何内容?
  • 它不会触发任何错误,也不会插入任何内容。如果我在create_order_item 函数中删除|&gt; order_item_changeset(attrs),它只会插入默认字段值。
  • create_order_item 返回什么?试试IO.inspect(Myapp.create_order_item(...))。它一定会返回一些错误。
  • 我明白了,它表明它在created_date.errors: [created_date: {"is invalid", [type: :utc_datetime, validation: :cast]}] 上有错误。我使用time_now = Ecto.DateTime.cast!(:calendar.universal_time_to_local_time(:calendar.universal_time())) 来获取当前插入时间。在我的架构中,我已经提交了@987654344 @.
  • 尝试删除Ecto.DateTime.cast!(只使用内部表达式,即time_now = :calendar.universal_time_to_local_time(:calendar.universal_time))。

标签: elixir phoenix-framework


【解决方案1】:

您的字段的类型为 utc_datetime,但您将 Ecto.DateTime 传递给它,它不能转换为 utc_datetime

iex(1)> Ecto.Type.cast(:utc_datetime, Ecto.DateTime.utc())
:error

相反,您可以直接传递 :calendar.universal_time_to_local_time/1 返回的 Erlang 日期时间元组:

time_now = :calendar.universal_time_to_local_time(:calendar.universal_time())

您也可以只使用:calendar.local_time(),其作用与上述相同:

time_now = :calendar.local_time()

另外,你真的应该在使用with 时处理失败案例,否则错误案例将被默默忽略,就像它在这里一样,直到我们在 cmets 中弄清楚:

with {:ok, %OrderItem{} = order_item} <- Myapp.create_order_item(...) do    
 ...
else
  {:error, error} ->
    # handle error
end

【讨论】: