dwyl / learn-phoenix

:fire: Phoenix is the web framework without compromise on speed, reliability or maintainability! Don't settle for less. :rocket:
650 stars 45 forks source link

...warning: `Ecto.Changeset.cast/4` is deprecated, please use `cast/3` + `validate_required/3` instead #35

Closed nelsonic closed 7 years ago

nelsonic commented 7 years ago

running mix test on page 134 but get the following warning message:

...warning: `Ecto.Changeset.cast/4` is deprecated, please use `cast/3` + `validate_required/3` instead
    (rumbl) web/models/video.ex:22: Rumbl.Video.changeset/2
    test/models/video_test.exs:15: Rumbl.VideoTest."test changeset with invalid attributes"/1
    (ex_unit) lib/ex_unit/runner.ex:296: ExUnit.Runner.exec_test/1
    (stdlib) timer.erl:166: :timer.tc/1

.warning: `Ecto.Changeset.cast/4` is deprecated, please use `cast/3` + `validate_required/3` instead
    (rumbl) web/models/video.ex:22: Rumbl.Video.changeset/2
    test/models/video_test.exs:10: Rumbl.VideoTest."test changeset with valid attributes"/1
    (ex_unit) lib/ex_unit/runner.ex:296: ExUnit.Runner.exec_test/1
    (stdlib) timer.erl:166: :timer.tc/1

image

Looked at: https://hexdocs.pm/ecto/Ecto.Changeset.html

tried changing the code in web/models/video.ex:20-25 from:

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @required_fields, @optional_fields)
    |> assoc_constraint(:category)
  end

To:

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @optional_fields)
    |> validate_required(params, @required_fields)
    |> assoc_constraint(:category)
  end

or:

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [@required_fields, @optional_fields]) # cast all fields as a single list
    |> validate_required(params, @required_fields)
    |> assoc_constraint(:category)
  end

but tests failed: image

figured I need to call cast on all the fields as a single list. read http://learningwithjb.com/posts/concat-lists-with-elixir So changed to:

  @required_fields ~w(url title description)
  @optional_fields ~w(category_id)
  @all_fields ~w(url title description category_id) # obviously not "DRY"

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @all_fields)
    |> validate_required(@required_fields)
    |> assoc_constraint(:category)
  end

and ran: mix test and got: test fail

I would like to continue spending time on this but I suspect that it will become clear to me later in the book or through more practice/understanding so I'm just going to leave this issue open in case someone else knows how to "fix" it ...

samhstn commented 7 years ago

@nelsonic I may be totally off the mark, but what happens if you change:

|> validate_required(params, @required_fields)

to

|> validate_required(@required_fields)

I tried something similar to that and it seemed to work (I'm not as far through the book as you so I can't run the example you are running just yet).

Jbarget commented 7 years ago

For anyone following "Programming Pheonix" around page 60:

@des-des and I were running into the same warnings and ended up doing the below

  def changeset(model, params \\ :invalid) do
    model
    |> cast(params, ~w(name username))
    |> validate_required([:name, :username])
    |> validate_length(:username, min: 1, max: 20)
  end

params is injected as the first argument to validate_required

untra commented 7 years ago

I would add to that: the book adds a uniqueness index to the username field, but doesn't suggest a way to validate that uniqueness:

 def changeset(model, params \\ :invalid) do
    model
    |> cast(params, ~w(name username))
    |> validate_required([:name, :username])
    |> unique_constraint(:username)
    |> validate_length(:username, min: 1, max: 20)
  end

I would recommend also adding the |> unique_constraint(:username) to the username validations

nelsonic commented 7 years ago

@untra thanks for sharing. I have a slight variation on this:

 def changeset(model, params \\ :invalid) do
    model
    |> cast(params, ~w(name username))
    |> validate_required([:name, :username])
    |> validate_length(:username, min: 1, max: 20)
    |> unique_constraint(:username) # save the unique_constraint for last as it "hits" the DB. ;-)
  end