Validating the length of a string

I’m trying to validate the length of a phone number in elixir’s ecto, below is the code I’m using

defmodule MyApp.Phone_number_Otp do
  use Ecto.Schema
  import Ecto.Changeset

  schema "phone_num_otps" do
    field :otp_code, :integer
    field :phone_num, :string
    field :phone_num_verified, :boolean, default: false
    field :phone_num_verified_at, :naive_datetime


  @min_chars 10
  @max_chars 13

  @doc false
  def changeset(phone_number__otp, attrs) do
    |> cast(attrs, [:phone_num, :otp_code, :phone_num_verified_at, :phone_num_verified])
    # |> validate_required([:phone_num, :otp_code, :phone_num_verified_at, :phone_num_verified])
    |> validate_required([:phone_num])
    |> validate_length(:phone_num, min: @min_chars, max: @max_chars)
    # |> validate_inclusion(:phone_num, 10..13)
    |> unique_constraint(:phone_num)

However, even when I post phone number’s length less than 10 chars and greater than 13, the changeset is able to insert data into postgres db… I’m still learning to work in ecto, so any help would be greatly appreciated. Please correct me where I’m going wrong.


Can we see your calling code where you perform the insert?
I’d also suggest to inspect the changeset IO.inspect changeset and check its :valid? and :errors fields.

Thank you @mathieuprog for the reply, yes the changeset is not valid, but I’m not sure how the phone number is being inserted in to the database. Here’s the report -

  action: nil,
  changes: %{},
  errors: [phone_num: {"can't be blank", [validation: :required]}],
  data: #MyApp.Phone_number_Otp<>,
  valid?: false

Looks good. I would now print the data IO.inspect and you can also show the code that passes the changeset to the Repo.insert function.

Here’s the output of data -

  __meta__: #Ecto.Schema.Metadata<:built, "phone_num_otps">,
  id: nil,
  inserted_at: nil,
  otp_code: nil,
  phone_num: nil,
  phone_num_verified: false,
  phone_num_verified_at: nil,
  updated_at: nil

I’m inserting the data into Postgres using the following code -

otp_code = Enum.random(10000..99999)
user = MyApp.Phone_number_Otp.changeset(%MyApp.Phone_number_Otp{}, params)


Repo.insert(%Phone_number_Otp{phone_num: phone_num, otp_code: otp_code})
user = MyApp.Phone_number_Otp.changeset(%MyApp.Phone_number_Otp{}, params)


Well you’re not passing the changeset (that has the invalid state) to insert

How can I do that, I’m still a noob in changeset stuff?

alias MyApp.PhoneNumberOtp

user_changeset = PhoneNumberOtp.changeset(%PhoneNumberOtp{}, params)


I would suggest to learn a little more regarding this topic; it’s really essential to understand how Changesets work when working with Ecto.

1 Like

Thanks man, I really appreciate your help… and also learn some more about this. Have a nice day and stay safe!

1 Like