Ecto Changesets/validations etc without a database

I hope this is a good place to ask this question about Ecto.

I am using Ecto for database access in my first Phoenix app, and I am in the middle of setting up authentication and I thought creating a table-less model for my login form might be a good way to go.

So I created a module called Alva.Login with a defstruct entry and tried to create a Changeset from it. But Ecto didn’t like that there wasn’t a schema associated with it.

My goal is to use Ecto’s validations/Phoenix.HTML.Form interface. For the time being I am just using my User model for my login form.

Has anybody had experience creating an Ecto schema with all virtual fields without being backed by a table in the database? This example is simple, but in the past I’ve used these “form” objects before in complex forms before stuffing the data into my actual models. This way, my forms can have different validations than the underlying models, and data can be organized differently.

5 Likes

I haven’t actually started learning Phoenix yet so you’ll have to excuse my answer being more general, but are you sure you need a tableless model? For login you could use a Sessions controller and form builders for the form itself?

This is what the create action would look like (again apologies as this is how I would do it in Rails):

  def create
    user = User.find_by_email(params[:email])
    if user && user.authenticate(params[:password])
      if params[:remember_me]
        cookies.permanent[:auth_token] = user.auth_token
      else
        cookies[:auth_token] = user.auth_token
      end
        redirect_to account_root_url, notice: "Successfully signed in!"
    else
      flash.now.alert = "Email or password is invalid"
      render "new"
    end
  end

The following cast can show you how to build auth from scratch (again apologies this is Rails) http://railscasts.com/episodes/250-authentication-from-scratch

If you really need a tableless model perhaps there is something like this in Phoenix? http://railscasts.com/episodes/219-active-model or http://railscasts.com/episodes/193-tableless-model

1 Like

Oh yeah, ActiveModel is exactly what I was thinking of. I haven’t seen anything exactly like it for Elixir, but with Phoenix’s Phoenix.HTML.Form module it wouldn’t be too difficult to make a validations layer interface with the form helpers.

The login example was probably too simple since it’s so easy to implement by hand.

I might try my hand at integrating an Elixir validations library with Phoenix’s HTML.Form. Seems like it would be a good first library to build in Elixir.

1 Like

I’m not actually using Phoenix’s HTML forms, so I am uncertain if it plays by it’s protocol rules. But I can recommend you Vex for creating form objects.

2 Likes

I have published a blog post that explores exactly this: http://blog.plataformatec.com.br/2016/05/ectos-insert_all-and-schemaless-queries/

TL;DR - Schemas in Ecto 2.0 map to any data source and, if you want, you can even drop schemas altogether when using repositories, changesets, etc.

13 Likes

Awesome!

There are so many places where this would be useful. Thanks!

I’ll give embedded_schemas a shot.

1 Like

I need to finally upgrade. This looks very good, @josevalim. Thank you for listening to community.

This looks so good, that in fact I would like to see that as stand-alone micro library, extracted from Ecto. My second candidate for similar extraction would be the migration mechanism. What are your thoughts on that? I could have one of our interns (supervised, restarted etc. ;)) having this done as a task this summer.

4 Likes

@caleb it took me a while but I have put together a blog post that may be helpful for you if you haven’t figured out yourself satisfactory ways of doing the above yet:

2 Likes

I believe @pragdave has a project for this at https://github.com/pragdave/data_division.

of course he has. How could I not think about that? :smiley:

I did a little research project into this direction too, but I basically learned that there is quite a lot code that needs to be first written and then maintained to remain in-line with phoenix_html & ecto. There is even more code needed when you want to support nested schemas or custom types - things Ecto ships with as well.

The other similar library I know of is mentioned above vex, with this adapter for https://github.com/jakub-zawislak/formex_vex for formex library. So if you use formex you can be all set with vex.

The advantage for me, when using Ecto, is that it’s already known and familiar API, and moreover - refactoring is pretty easy. You can first write your stuff in schemas, then refactor by copying over changeset/2 and custom casting/validations to a service module. And you don’t need an additional dependency that will have it’s own quirks (@pragdave’s lib looks young and not complete, it might be very well a research project like mine :)).

2 Likes

I was trying now to require only ecto_changeset to my Mnesia based project but realized that I need instead to require the entire ecto library.

Any plans for this extraction to happen in the future @michalmuskala or @josevalim?

ecto_sql was already extracted from ecto, so you’re not pulling in any sql/adapter specific code when using ecto already.

From ecto_sql mix.exs:

defp ecto_dep do
    if path = System.get_env("ECTO_PATH") do
      {:ecto, path: path}
    else
      {:ecto, "~> 3.4.3"}
    end
  end

Yeah, ecto_sql depends on ecto, but ecto doesn’t depend on ecto_sql. So you can use ecto without all the actual database connection stuff.

But still a lot of stuff there that isn’t necessary to just use Ecto Changesets or am I wrong?

I guess Ecto.Repo and Ecto.Query/Ecto.Multi are not strictly necessary, but Ecto.Schema, Ecto.Typo, Ecto.Association (and likely more) are all parts you’d use with changesets.

1 Like