【问题标题】:Elixir Ecto Insert empty belongs_toElixir Ecto 插入空的 belongs_to
【发布时间】:2016-07-25 08:14:31
【问题描述】:

首先:我找到了这个topic,但它不起作用。

我有两个模型之间的关系

Council(1)<->(n)Department

我想插入一个与部门没有关系的委员会。

我有这个 ecto 架构:

schema "councils" do
  field :name, :string
  field :description, :string
  belongs_to :department, Db2.Department
  many_to_many :students, Db2.Student, join_through: Db2.StudentCouncil
  many_to_many :periods, Db2.Period, join_through: Db2.StudentCouncil

  timestamps()
end

使用此 SQL 架构:

CREATE TABLE public.councils
(
  id integer NOT NULL DEFAULT nextval('councils_id_seq'::regclass),
  name character varying(255),
  description character varying(255),
  department_id integer,
  inserted_at timestamp without time zone NOT NULL,
  updated_at timestamp without time zone NOT NULL,
  CONSTRAINT councils_pkey PRIMARY KEY (id),
  CONSTRAINT councils_department_id_fkey FOREIGN KEY (department_id)
      REFERENCES public.departments (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

文档说 cast/4 已弃用,但 phoenix 自己创建了带有 cast/3validate_required/3 的变更集。我只添加了department,所以我有以下变更集:

def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, [:name, :description, :department_id])
  |> validate_required([:name])
  |> unique_constraint(:name)
  |> assoc_constraint(:department)
end

对于表单,我使用默认的 phoenix.html 表单元素。 当我提交表单时,凤凰说:

[debug] QUERY OK db=1.2ms queue=0.1ms
SELECT u0."id", u0."uid", u0."is_admin", u0."is_staff", u0."password_hash", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1) [1]
[debug] Processing by Db2.CouncilController.create/2
Parameters: %{"_csrf_token" => "KwpdFCZ/bFN9fwkcXSAYLhRCIzgOAAAAXeoEa4+d1MoT7SvzZpgOdg==", "_utf8" => "✓", "council" => %{"department_id" => "", "description" => "", "name" => "test2"}}
  Pipelines: [:browser]
[debug] QUERY OK db=1.2ms queue=0.1ms


#Ecto.Changeset<action: :insert, changes: %{description: "", name: "test2"},
  errors: [department_id: {"is invalid", [type: :id]}], data: #Db2.Council<>,
  valid?: false>

【问题讨论】:

    标签: elixir phoenix-framework ecto


    【解决方案1】:

    问题是您发送一个空字符串作为department_id 而不是nil。空字符串不会自动转换为nil

    iex(1)> MyApp.Post.changeset %MyApp.Post{}, %{"title" => "Hello"}
    #Ecto.Changeset<action: nil, changes: %{title: "Hello"}, errors: [],
     data: #MyApp.Post<>, valid?: true>
    iex(2)> MyApp.Post.changeset %MyApp.Post{}, %{"title" => "Hello", "user_id" => nil}
    #Ecto.Changeset<action: nil, changes: %{title: "Hello"}, errors: [],
     data: #MyApp.Post<>, valid?: true>
    iex(3)> MyApp.Post.changeset %MyApp.Post{}, %{"title" => "Hello", "user_id" => "1"}
    #Ecto.Changeset<action: nil, changes: %{title: "Hello", user_id: 1}, errors: [],
     data: #MyApp.Post<>, valid?: true>
    iex(4)> MyApp.Post.changeset %MyApp.Post{}, %{"title" => "Hello", "user_id" => ""}
    #Ecto.Changeset<action: nil, changes: %{title: "Hello"},
     errors: [user_id: {"is invalid", [type: :id]}], data: #MyApp.Post<>,
     valid?: false>
    

    您可以在调用changeset 之前将department_id 显式设置为nil,或者使用Phoenix 的scrub_params 插件,它对所有空字符串执行相同的操作:

    # web/controllers/council_controller.ex
    plug :scrub_params, "council" when action in [:create]
    

    (将"council" 更改为字段名称,将[:create] 更改为您接受该字段的操作列表。)

    【讨论】:

    • woOt?谢谢你。像魅力一样工作:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 2016-10-26
    • 1970-01-01
    相关资源
    最近更新 更多