ecto 模型参数未验证?
ecto model parameter not validated?
可能是我遗漏了一些东西,但感觉这应该是一条无效记录:
pry(1)> project_params
%{"name" => ""}
pry(2)> changeset
%Ecto.Changeset{action: nil, changes: %{name: ""}, constraints: [], errors: [],
filters: %{},
model: %Elix.Project{__meta__: #Ecto.Schema.Metadata<:built>, id: nil,
inserted_at: nil, name: nil, updated_at: nil,
user: #Ecto.Association.NotLoaded<association :user is not loaded>,
user_id: 2}, optional: [], opts: [], params: %{"name" => ""}, prepare: [],
repo: nil, required: [:name, :user_id],
types: %{id: :id, inserted_at: Ecto.DateTime, name: :string,
updated_at: Ecto.DateTime, user_id: :id}, valid?: true, validations: []}
pry(3)> changeset.valid?
true
以下是我定义模型的方式:
项目
defmodule Elix.Project do
use Elix.Web, :model
schema "projects" do
field :name, :string
belongs_to :user, Elix.User
timestamps
end
@required_fields ~w(name user_id)
@optional_fields ~w()
@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)
end
end
用户
defmodule Elix.User do
use Elix.Web, :model
schema "users" do
field :email, :string
field :password, :string, virtual: true
field :crypted_password, :string
has_many :projects, Elix.Project
timestamps
end
@required_fields ~w(email password)
@optional_fields ~w()
@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)
|> unique_constraint(:email)
|> validate_format(:email, ~r/@/)
|> validate_length(:password, min: 5)
end
end
这是控制器创建操作的代码:
def create(conn, %{"project" => project_params}) do
changeset =
Ecto.build_assoc(conn.assigns.current_user, :projects) |>
Project.changeset(project_params)
IEx.pry
case Repo.insert(changeset) do
{:ok, project} ->
conn
|> put_flash(:info, "Project #{project.name} created succesfully")
|> redirect(to: project_path(conn, :index))
{:error, changeset} ->
render(conn, "new.html", project: changeset)
end
end
我故意没有输入任何内容就提交了表单,这样我就可以测试表单显示错误。我在这里错过了什么?
如果name
的值为nil
,则changeset.valid?
只会是false
。由于 name
在您的情况下的值为空字符串,因此变更集将有效。
处理将空字符串作为值传递的表单的最佳位置是在控制器中添加 scrub_params
插件,如下所示:
plug :scrub_params, "project" when action in [:create, :update]
查看 documentation 了解有关 scrub_params
的更多信息。
可能是我遗漏了一些东西,但感觉这应该是一条无效记录:
pry(1)> project_params
%{"name" => ""}
pry(2)> changeset
%Ecto.Changeset{action: nil, changes: %{name: ""}, constraints: [], errors: [],
filters: %{},
model: %Elix.Project{__meta__: #Ecto.Schema.Metadata<:built>, id: nil,
inserted_at: nil, name: nil, updated_at: nil,
user: #Ecto.Association.NotLoaded<association :user is not loaded>,
user_id: 2}, optional: [], opts: [], params: %{"name" => ""}, prepare: [],
repo: nil, required: [:name, :user_id],
types: %{id: :id, inserted_at: Ecto.DateTime, name: :string,
updated_at: Ecto.DateTime, user_id: :id}, valid?: true, validations: []}
pry(3)> changeset.valid?
true
以下是我定义模型的方式:
项目
defmodule Elix.Project do
use Elix.Web, :model
schema "projects" do
field :name, :string
belongs_to :user, Elix.User
timestamps
end
@required_fields ~w(name user_id)
@optional_fields ~w()
@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)
end
end
用户
defmodule Elix.User do
use Elix.Web, :model
schema "users" do
field :email, :string
field :password, :string, virtual: true
field :crypted_password, :string
has_many :projects, Elix.Project
timestamps
end
@required_fields ~w(email password)
@optional_fields ~w()
@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)
|> unique_constraint(:email)
|> validate_format(:email, ~r/@/)
|> validate_length(:password, min: 5)
end
end
这是控制器创建操作的代码:
def create(conn, %{"project" => project_params}) do
changeset =
Ecto.build_assoc(conn.assigns.current_user, :projects) |>
Project.changeset(project_params)
IEx.pry
case Repo.insert(changeset) do
{:ok, project} ->
conn
|> put_flash(:info, "Project #{project.name} created succesfully")
|> redirect(to: project_path(conn, :index))
{:error, changeset} ->
render(conn, "new.html", project: changeset)
end
end
我故意没有输入任何内容就提交了表单,这样我就可以测试表单显示错误。我在这里错过了什么?
如果name
的值为nil
,则changeset.valid?
只会是false
。由于 name
在您的情况下的值为空字符串,因此变更集将有效。
处理将空字符串作为值传递的表单的最佳位置是在控制器中添加 scrub_params
插件,如下所示:
plug :scrub_params, "project" when action in [:create, :update]
查看 documentation 了解有关 scrub_params
的更多信息。