2016-06-20 7 views
1

は、私は何かが欠けてることかもしれませんが、これは無効なレコードされている必要があることを感じている:エクトモデルパラメータが検証されていませんか?

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 

私は、フォームの表示エラーをテストする可能性があるように私は、意図的に何も入力せずにフォームを送信しています。私はここで何が欠けていますか?

+0

コントローラの[:create、:update] 'のアクションに' plug:scrub_params、 "project"がありますか? – AbM

+0

私はそうではありません。空文字列は有効と見なされますか? – Geo

+0

ええ、空の文字列が有効です。これが 'scrub_params'の目的です。空の文字列を 'nil'にします – AbM

答えて

2

nameの値がnilの場合、changeset.valid?は、falseになります。あなたのケースのnameの値は空の文字列なので、チェンジセットは有効です。

値として空の文字列を渡すフォームに対処するのに最適な場所は、scrub_paramsがそうのようなプラグイン追加することにより、コントローラである:

plug :scrub_params, "project" when action in [:create, :update]

scrub_params詳細はdocumentationを確認してください。

+2

名前が空でない場合は、ビジネスロジックの一部ですが、私は確かにあなたのパスワードのようにその長さのバリデータを追加します。 'scrub_params'は素晴らしいですが、将来コントローラの中で誤って実行することを忘れてしまうのは簡単です。長さバリデーターを入れる方が安全で、 'scrub_params'を入れてもかまいません。 –

+0

あなたは正しいです。私は、デフォルトでエクトがそれを処理するという印象の下にあっただけです:) – Geo

関連する問題