Can't create new entry in database

Perhaps try requiring it first. require BookList.User

I used mix phx.new --no-brunch --no-html book_list and have lib/book_list and lib/book_list_web. See session below. Can’t figure out what is wrong.

$ iex -S mix phoenix.server
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

mix phoenix.server is deprecated. Use phx.server instead.
[info] Running BookListWeb.Endpoint with Cowboy using http://0.0.0.0:4000
Interactive Elixir (1.6.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> BookList.User.__info__(:functions)
** (UndefinedFunctionError) function BookList.User.__info__/1 is undefined (module BookList.User is not available)
    BookList.User.__info__(:functions)

iex(1)> require BookList.Use
** (CompileError) iex:1: module BookList.Use is not loaded and could not be found

You forgot the r in BookList.User

Where is that user.ex? (phx.new wouldn’t create that web directory.)

In a “healthy project”:

iex(2)> Rumbl.Accounts.User.__info__(:functions)
[
  __changeset__: 0,
  __schema__: 1,
  __schema__: 2,
  __struct__: 0,
  __struct__: 1,
  changeset: 2,
  registration_changeset: 2
]

for rumbl/lib/rumbl/accounts/user.ex

Assuming you’re using Phoenix 1.3, try replacing use BookList.Web, :model with use Ecto.Schema and import Ecto.Changeset. But I agree with @peerreynders, the existence of separate web and lib directories suggests that something’s not kosher. Are you sure you’re using 1.3?

1 Like

Sorry, typo, but the result is the same:

iex(2)> require BookList.User
** (CompileError) iex:2: module BookList.User is not loaded and could not be found

How do I check the Phoenix version?

The project version is listed in mix.exs:

  defp deps do
    [
      {:phoenix, "~> 1.3.2"},
      {:phoenix_pubsub, "~> 1.0"},
      {:phoenix_ecto, "~> 3.2"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_html, "~> 2.10"},
      {:phoenix_live_reload, "~> 1.0", only: :dev},
      {:gettext, "~> 0.11"},
      {:cowboy, "~> 1.0"},
      {:comeonin, "~> 4.1"},
      {:bcrypt_elixir, "~> 1.0"}
    ]
  end

For the installed version:

$ mix phx.new --version
Phoenix v1.3.2

You can check the version of the phoenix mix archive by running mix phx.new -v.

This is what I have:’

 $ mix phx.new --version
Phoenix v1.3.2

Maybe I should start over. I was just setting up this project, so no harm would be done. Does seem fishy.

A 1.3 project created with phoenix.new would create book_list/web/web.ex which contains:

defmodule BookList.Web do
  # ...

  def model do
    quote do
      # Define common model functionality
    end
  end

A 1.3 project created with phx.new would create book_list/lib/book_list_web.ex which contains:

defmodule BookListWeb do
  # ...

without any model definition.

So use BookList.Web, :model couldn’t work in a phx.new project.

1 Like

You might want to try out the Phoenix generators to get a feel for how things go together. https://hexdocs.pm/phoenix/Mix.Tasks.Phoenix.Gen.Html.html#content

Or

https://hexdocs.pm/phoenix/Mix.Tasks.Phoenix.Gen.Model.html#content

Those links discuss the old style generators (phoenix.gen) which are only relevant for existing applications. For new applications only the new style generators (phx.gen) should be used.

Like: https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Json.html#content

1 Like

My previous troubles arose from mixing phoenix and phx – I had been using generators, as in the session below. So here is a new try with

  660  mix phx.new --no-brunch --no-html book_list
  661  cd book_list/
  662  atom .
  663  mix phx.gen.json BookSpace User users username:string email:string
  664  mix ecto.migrate

T’his gives the error

$ mix ecto.migrate
Compiling 16 files (.ex)

== Compilation error in file lib/book_list_web/controllers/user_controller.ex ==
** (CompileError) lib/book_list_web/controllers/user_controller.ex:18: undefined function user_path/3
    (stdlib) lists.erl:1338: :lists.foreach/2
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:198: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

I would expect this to work with the --no-html flag, but it’s not working for me either. However, without the --no-html flag, and running mix ecto.create before migrating works

Did you do this, it’s part of the output after generating the new project:

Add the resource to your :api scope in lib/book_list_web/router.ex:

resources "/users", UserController, except: [:new, :edit]

In your current project the /api scope is commented out. But even if it wasn’t there would be no entry for the User schema.

You just need to uncomment the /api scope and add the entry. The user_path/3 function is path helper so it’s trying to return a path based on a route definition which doesn’t exist in this scenario.

Here’s a link to some information on path helpers.
https://hexdocs.pm/phoenix/routing.html#path-helpers

Hope that helps
Paul

2 Likes

Thank you all !!

The solution: (1) Use the phx prefix consistently – no mixing with phoenix; (2) The phx generators require a context module name before the model module name and its lowercase plural; (3) You have to add the route, as @paulsullivanjr noted – this is not done automatically.

All working now; I very much appreciate everyone’s help.

1 Like

I’d go as far as saying forget about models (essentially what phx does by shifting from mix phoenix.gen.model to mix phx.gen.schema).

mix phx.gen.context is largely a convenience tool rather than a prescription for contexts:

mix phx.gen.context Accounts User users name:string age:integer

simply creates the persisted User data type inside the Accounts context (which is created if it doesn’t already exist). The generator doesn’t convey that

  • a single context can have multiple persisted data types
  • the type persisted may not be the type that is shared through the module API because the persisted type may contain details that are appropriate for internal context use only.

In the simplest terms “model” has a habit of putting the data type persisted as a table front and center based on an oversimplified “wiring” of resource based Server MVC:

GET resource/:id    → SELECT * FROM resource WHERE id = :id
POST resource       → INSERT INTO resource 
PUT resource/:id    → UPDATE resource WHERE id = :id
DELETE resource/:id → DELETE resource WHERE id = :id

The CRUD oversimplification isn’t what REpresentational State Transfer is all about. For example creating a “money transfer resource” could be responsible updating the two accounts represented in the state of the resource.

In contrast to “model” the context is supposed to put related behaviour front and center - at the same time giving the context autonomy over its internal data types and how they are persisted. So an E-commerce site could have Sales, Billing, Shipping contexts while Sales and Shipping each have their own internal Product type (collaborating via some common Product Key or public (non-persisted) Product type). And contexts aren’t about REST resources - they deal with domain types and their behaviours.

1 Like

Thank you very much. This is a great help!

I should note however that even Programming Phoenix ≥ 1.4 still advocates this implementation of “Phoenix MVC”:

48%20PM

The “model” is the collection of persisted data types, the associated queries, and changesets - but without Repo access. This is justified by striving to keep everything inside the “model” free from side effects, leaving it ultimately up to the controller to effect changes in persisted state by pushing the built-up changesets into the appropriate Repo functions.

This is in contrast to the typical understanding of a bounded context which puts a boundary around its internal types (and associated transformations usually implemented in a persistence-ignorant manner with direct access to/on top of a Repository)

(Edit: some of the Programming Phoenix ≥ 1.4 code actually looks less like the above graphic as context functions will access the Ecto repo themselves - in which case side effects are accepted in order to keep implementation details out of the controller)

“Phoenix MVC” is the basis of Dave Thomas’s claim that:

first 1.2 and then 1.3 actually tightened the coupling between the two.

[i.e. Phoenix and Ecto] - making a case for removing the database (and Ecto) entirely out of Phoenix and using them inside a separate OTP component (OTP application) which exposes an API to which Phoenix connects.

28%20PM

2 Likes