Ecto and NOT NULL constraint (beginner question)

Hi there,

I am beginning Phoenix/Ecto (coming from Rails as many) and I found myself puzzled by how to handler columns with a NOT NULL constraint.

I have a basic User Schema as follows:

schema "users" do
    field :email, :string
    field :first_name, :string
    field :last_name, :string
end

And NOT NULL constraint on all fields (among other things). I would like to handle this through Ecto, so I added two Ecto.Changesets: one on for creation and one for update as follows:

def changeset(user, attrs) do
  user
  |> cast(attrs, [:first_name, :last_name, :email])
end

def creation_changeset(user, attrs) do
  user
  |> changeset(attrs)
  |> validate_required(attrs, [:first_name, :last_name, :email])
end

The creation_changeset\2 method works as expected: it does not allow creation without all fields, and any “blank” value is reported correctly.

The Changeset\2 method does not work correclty, if I do something like:

some_user
|> User.changeset(%{email: nil, first_name: nil, last_name: nil})

I get a valid Ecto.Changeset with changes: %{email: nil, first_name: nil, last_name: nil} and when sent to the database (via Repo.update\1) it raises a Postgrex.Error instead a returning an erroneous Changeset…

Does anybody know how to get this right ?
It feels super basic but I could not understand how to do it :cry:

Regards

Any reason why You use a different changeset for create and update? In that case it seems enough to have only one.

def changeset(user, attrs) do
  user
  |> changeset(attrs)
  |> validate_required(attrs, [:first_name, :last_name, :email])
end

In your case, as the changeset does not use validate_required, it’s expected to be valid, but the db will not accept it.

2 Likes

Also worth to mention it’s like a two ways validation…

  • One happens before any db calls, it does validate the shape of data transmitted to db.
  • The second after db calls, eg. checks for unique constraints…

Thx a lot kokolegorille (français/francophone ??) for the answers.

To give you the big picture, I want to build some Rails-like resource API.

So I want to accept “partial updates”, such as:

# Change only first_name
%{first_name: "Steve"}

# Change only last_name and email
%{last_name: "Jobs", email: "steve@apple.com"}

My current understanding (more of a guess really…) is that if I pass all the fields into validate_required\4 it will not accept “partial” updates (since they are marked as required).

Or maybe I just don’t get how validate_required works…

Oui francophone :slight_smile:

Bonjour et bienvenue.

The difference is how You call changeset…

You can pass a new user, or an existing user. When You update, You are passing an existing struct, with maybe new params.

It will work for partial update, because of the existing user being passed to the changeset.

eg… in the context

  # In case of create, You pass an empty struct

  def create_user(attrs \\ %{}) do
    %User{}
    |> User.changeset(attrs)
    |> Repo.insert()
  end

  # In case of update... You pass an existing user

  def update_user(%User{} = user, attrs) do
    user
    |> User.changeset(attrs)
    |> Repo.update()
  end

ok thanks, this is much better.

I’m still getting confused with the params, changes & data fields of the Ecto.Changeset and how everything interacts, this is still very new to me…

Now I’m going to test your solution and re-read the hex docs one again with these in mind.

Lots of kudos for all the help !

Coming from Rails too, it’s been difficult to transition from Active Record. It’s simply different.

I advise You this free resource

http://pages.plataformatec.com.br/ebook-whats-new-in-ecto-2-0

although Ecto is now 3.x.

Or

1 Like

Yeah, validate_required can be a bit confusing and I think we recently updated the docs, but validate_required does not work only on the parameters but it works on the both the parameter and the data. So validate_required will only trigger if there are no params and the current value for it also nil. This allows you to perform partial updates.

2 Likes

I bought the “Programming Phoenix 1.4” from PragProg which is super cool, and will check the book on Ecto too.
Did you read it ? it is worth the price ??

As a seasoned Rails developer I have a lot on scenarios in mind I want to be able translate to Phoenix before I feel “operational”.
Btw the support on this forum is really awesome, quick straight-to-the-point answers !

I liked the book on Ecto… Like almost all the resources on Elixir and Erlang.

It’s good if You want to persists data into db.

But when I started, I was more interested in OTP. You will quickly see there are tons of way to persists data, into processes, ets, dets, mnesia etc.

And it’s different to think web as a stateful place (You might not need to do db query to get application state)

PS. You can search the forum for book discounts, because Manning and PragProg are forum partners… (35% to members)

Yes. However just to set expectations:

i.e. SQL competence is a valuable asset when building Ecto skills.

4 Likes

Programming Ecto is excellent in my opinion. I recommend it.

@mikemccall @peerreynders I just ordered both Programming Ecto (beta) and Metaprogramming Elixir, so hopefully they will help move forward !

I’m currently porting a medium-sized Rails app to Phoenix, taking my time to do it correctly. Coding a real project is the only way I learn something (book-only doesn’t really work with me…) but it’s hard to move away from a stack you know well :grimacing:
I will probably come back regularly to the forum while moving forward though, hope to see you all here !

Btw, any opinion on Functional Web Development with Elixir, OTP, and Phoenix, also on pragprog ?

I don’t know that “just reading” these books can really help anyone but fortunately they are set up to have you working through code. I’ve been using the “Programming Ecto” playground script and music_db in various topics for demonstration purposes (I went through B1.0 Chapters1-7 back in June).

Of all the pragprog Elixir books I’d rate Metaprogramming Elixir as the most challenging one - so that one is likely best enjoyed in small doses (Don’t Write Macros But Do Learn How They Work).

any opinion on Functional Web Development with Elixir, OTP, and Phoenix,

I worked through the chapters that were available before the rewrite. I recommend it for getting more into the “thinking in processes” mindset and would definitiely tackle it before Metaprogramming Elixir.

I finished this book not too long ago. It was ok. I hope others with more elixir experience have better feedback. My main gripe is there is way too much focus on managing the game. I kind of wish they used something like tic tac toe so more focus could be put on OTP.

I recently picked up Elixir In Action and so far it’s great and I think it provides more value in regards to “thinking in processes”.

1 Like

So my data is being saved into the database with a nil, but if I am understanding correctly nil is accepted even when I mark the field as required? If so how can I enforce the changeset to fail, because that is what I expect from a required field :wink:

No, validate_required should add an error if both the parameter and the data field are nil. Please provide a failing test case to Ecto’s suite if you are seeing otherwise.