Changeset/1 undefined

I’m trying to create a contact email form with the context of Contact >Emails, however I’m running into changeset problems and I’ve been going round in circles trying to solve it.

The changeset is within my email.ex file:

defmodule Iotc.Contact.Email do
  use Ecto.Schema
  import Ecto.Changeset
  alias Iotc.Contact.Email


  schema "contact_emails" do
    field :email, :string
    field :event, :string
    field :message, :string
    field :name, :string

    timestamps()
  end


  def changeset(%Email{} = email, attrs) do
    email
    |> cast(attrs, [:name, :email, :message, :event])
    |> validate_required([:name, :email, :message])
  end
end

And my email_controller.ex has the following:

defmodule Iotc.Web.EmailController do
  use Iotc.Web, :controller
  alias Iotc.Contact

  def index(conn, _params) do
    changeset = Contact.Email.changeset(%Contact.Email{})
    emails = Contact.list_emails()
    render(conn, "index.html", emails: emails, changeset: changeset)
  end

  def new(conn, _params) do
    changeset = Contact.changeset(%Contact.Email{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"email" => email_params}) do
    changeset = Contact.changeset(%Iotc.Contact.Email{}, email_params)
    case Contact.create_email(changeset) do
      {:ok, email} ->
        conn
        |> put_flash(:info, "Email sent")
        |> redirect(to: email_path(conn, :index))
      {:error, changeset} ->
        conn
        |> put_flash(:error, "Something went wrong")
        |> render("index.html", changeset: changeset)
    end
  end

That current set up gives me function Iotc.Contact.Email.changeset/1 is undefined or private so I’ve tried changeset = Contact.changeset(%Email{}) as well, but this gives me another error of ib/iotc/web/controllers/email_controller.ex:6: Email.__struct__/1 is undefined, cannot expand struct Email.

This isp probably so simply, but I’ve now gone blind.

1 Like

Your changeset is defined inside Contact.Email, not Contact

The error function Iotc.Contact.Email.changeset/1 is undefined or private say why the reason of you error, you had define a function with arity 2, on call function you give only one param, you call should be:

def new(conn, params) do
changeset = Contact.changeset(%Contact.Email{}, params)
render(conn, “new.html”, changeset: changeset)
end

or you can change the function signature on Iotc.Contact.Email to include default value of attrs param like this:

> def changeset(%Email{} = email, attrs \\ %{}) do
>     email
>     |> cast(attrs, [:name, :email, :message, :event])
>     |> validate_required([:name, :email, :message])
>   end
1 Like

Yes. So how do I call that correctly from my controller? Doesn’t changeset = Contact.Email.changeset already do that. Or can I change the alias to Iotc.Contact.Email?

As @Cleidiano mentionned, it’s an arity problem, You don’t have changeset/1, you have changeset/2

You have defined…

def changeset(%Email{} = email, attrs) do … end

but You are using…

changeset = Contact.Email.changeset(%Contact.Email{})

Thanks.

However, if I use:

  def new(conn, params) do
    changeset = Contact.changeset(%Contact.Email{}, params)
    render(conn, "new.html", changeset: changeset)
  end

As per @Cleidiano suggestion, I just get function Iotc.Contact.changeset/2 is undefined or private.

As you might be able to tell, I’m new to this! :wink:

I also just generated the code via mix phx.gen.html so I guess I don’t understand the real workings of what needs to be changed from what Phoenix generates.

Because You must use Contact.Email.changeset…

Using phx generator means You are using phoenix 1.3

So there is this context boundary :slight_smile:

and Contact is your boundary, where You should define all the functions for the contact boundary.

That is why they use Contact.changeset. You should have a look at the Contact.ex file and see what is inside

Makes sense.

We might be getting somewhere, as I now get a new error: assign @changeset not available in eex template.

My form looks like:

<%= form_for @changeset, email_path(@conn, :create), fn f -> %>

That was an issue with my render tag.

Sorted.

Thanks for the advice.

You have a lot of Contact.changeset(%Contact.Email{}) in your controller

In particular in the new action.

I guess if You have a form, you are either doing new or edit

BTW I don’t see the need to pass a changeset in the index action.

I don’t use generators, is your controller generated automaticaly?

Yeah the controller was generated automatically. I’m going to go through and clean it up as you’re right, there’s a lot in there I don’t need.