长生不老药 naive_datetime 施放错误
elixir ecto naive_datetime cast error
在我的 ecto 模型中,我需要在字段中指定:user_timestamp 从 unix_time 转换而来的时间。
迁移:
def change do
alter table(:operations) do
add :user_timestamp, :naive_datetime, null: false
end
end
我的operation.ex
schema "operations" do
field :sum, :float
field :name, :string
field :user_timestamp, :naive_datetime
timestamps()
end
def changeset(struct, params \ %{}) do
struct
|> cast(params, [:name, :sum, :user_timestamp])
|> validate_required([:sum, :user_timestamp])
|> convert_unix_time_to_ecto
end
defp convert_unix_time_to_ecto(changeset) do
put_change(changeset, :user_timestamp, Ecto.DateTime.from_unix!(changeset.changes.user_timestamp, :seconds) |> Ecto.DateTime.to_naive())
end
但是当我尝试添加具有 user_timestamp 的要求时,出现错误:
[error] #PID<0.492.0> running MyApp.Endpoint terminated
Server: localhost:4000 (http)
Request: POST /api/v1/operations
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in Ecto.Type.cast_naive_datetime/1
(ecto) lib/ecto/type.ex:761: Ecto.Type.cast_naive_datetime(1492722276)
(ecto) lib/ecto/changeset.ex:523: Ecto.Changeset.cast_field/8
(ecto) lib/ecto/changeset.ex:482: Ecto.Changeset.process_param/8
(elixir) lib/enum.ex:1325: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(elixir) lib/enum.ex:1325: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(ecto) lib/ecto/changeset.ex:450: Ecto.Changeset.do_cast/7
(my_app) web/models/operation.ex:25: MyApp.Operation.changeset/2
(my_app) web/models/operation.ex:32: MyApp.Operation.create_changeset/2
(my_app) web/controllers/v1/operation_controller.ex:25: MyApp.V1.OperationController.create/2
(my_app) web/controllers/v1/operation_controller.ex:1: MyApp.V1.OperationController.action/2
(my_app) web/controllers/v1/operation_controller.ex:1: MyApp.V1.OperationController.phoenix_controller_pipeline/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.instrument/4
(my_app) lib/phoenix/router.ex:261: MyApp.Router.dispatch/2
(my_app) web/router.ex:1: MyApp.Router.do_call/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.phoenix_pipeline/1
(my_app) lib/plug/debugger.ex:123: MyApp.Endpoint."call (overridable 3)"/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /home/mars/phoenix_projects/my_app/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
如何纠正这个错误?
在您的转换代码有机会 运行 之前,它在 cast
中失败了。
将 :user_timestamp
排除在转换字段列表之外,并使用 put_change
和 validate_required
之前的转换值。
def changeset(struct, params \ %{}) do
struct
|> cast(params, [:name, :sum])
|> convert_unix_time_to_ecto(params["user_timestamp"])
|> validate_required([:sum, :user_timestamp])
end
defp convert_unix_time_to_ecto(changeset, nil), do: changeset
defp convert_unix_time_to_ecto(changeset, timestamp) do
datetime =
timestamp
|> DateTime.from_unix!(:seconds)
|> DateTime.to_naive()
put_change(changeset, :user_timestamp, datetime)
end
一种选择是使用 virtual fields。
在我的 ecto 模型中,我需要在字段中指定:user_timestamp 从 unix_time 转换而来的时间。 迁移:
def change do
alter table(:operations) do
add :user_timestamp, :naive_datetime, null: false
end
end
我的operation.ex
schema "operations" do
field :sum, :float
field :name, :string
field :user_timestamp, :naive_datetime
timestamps()
end
def changeset(struct, params \ %{}) do
struct
|> cast(params, [:name, :sum, :user_timestamp])
|> validate_required([:sum, :user_timestamp])
|> convert_unix_time_to_ecto
end
defp convert_unix_time_to_ecto(changeset) do
put_change(changeset, :user_timestamp, Ecto.DateTime.from_unix!(changeset.changes.user_timestamp, :seconds) |> Ecto.DateTime.to_naive())
end
但是当我尝试添加具有 user_timestamp 的要求时,出现错误:
[error] #PID<0.492.0> running MyApp.Endpoint terminated
Server: localhost:4000 (http)
Request: POST /api/v1/operations
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in Ecto.Type.cast_naive_datetime/1
(ecto) lib/ecto/type.ex:761: Ecto.Type.cast_naive_datetime(1492722276)
(ecto) lib/ecto/changeset.ex:523: Ecto.Changeset.cast_field/8
(ecto) lib/ecto/changeset.ex:482: Ecto.Changeset.process_param/8
(elixir) lib/enum.ex:1325: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(elixir) lib/enum.ex:1325: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(ecto) lib/ecto/changeset.ex:450: Ecto.Changeset.do_cast/7
(my_app) web/models/operation.ex:25: MyApp.Operation.changeset/2
(my_app) web/models/operation.ex:32: MyApp.Operation.create_changeset/2
(my_app) web/controllers/v1/operation_controller.ex:25: MyApp.V1.OperationController.create/2
(my_app) web/controllers/v1/operation_controller.ex:1: MyApp.V1.OperationController.action/2
(my_app) web/controllers/v1/operation_controller.ex:1: MyApp.V1.OperationController.phoenix_controller_pipeline/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.instrument/4
(my_app) lib/phoenix/router.ex:261: MyApp.Router.dispatch/2
(my_app) web/router.ex:1: MyApp.Router.do_call/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.phoenix_pipeline/1
(my_app) lib/plug/debugger.ex:123: MyApp.Endpoint."call (overridable 3)"/2
(my_app) lib/my_app/endpoint.ex:1: MyApp.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /home/mars/phoenix_projects/my_app/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
如何纠正这个错误?
在您的转换代码有机会 运行 之前,它在 cast
中失败了。
将 :user_timestamp
排除在转换字段列表之外,并使用 put_change
和 validate_required
之前的转换值。
def changeset(struct, params \ %{}) do
struct
|> cast(params, [:name, :sum])
|> convert_unix_time_to_ecto(params["user_timestamp"])
|> validate_required([:sum, :user_timestamp])
end
defp convert_unix_time_to_ecto(changeset, nil), do: changeset
defp convert_unix_time_to_ecto(changeset, timestamp) do
datetime =
timestamp
|> DateTime.from_unix!(:seconds)
|> DateTime.to_naive()
put_change(changeset, :user_timestamp, datetime)
end
一种选择是使用 virtual fields。