PavelZX

PavelZX

In Phx 1.3 this code works, but in Phx 1.4 doesn’t want.

  def index(conn, _params) do
    current_user = Guardian.Plug.current_resource(conn)

    owned_board = current_user
      |> assoc(:owned_board)
      |> board_preload_all
      |> Repo.all

    invited_board = current_user
      |> assoc(:board)
      |> not_owned_by(current_user.id)
      |> board_preload_all
      |> Repo.all

    render(conn, "index.json", owned_board: owned_board, invited_board: invited_board)
  end

Errors are obtained.

[error] #PID<0.501.0> running ImconWeb.Endpoint (connection #PID<0.500.0>, stream id 1) terminated
Server: caix.ru:4001 (http)
Request: POST /api/v1/sessions
** (exit) an exception was raised:
    ** (ArgumentError) argument error
        :erlang.apply(%Imcon.Auth.User{__meta__: #Ecto.Schema.Metadata<:loaded, "user">, board: #Ecto.Association.NotLoaded<association :board is not loaded>, email: "john@phoenix-trello.com", encrypted_password: "$2b$12$nn1jeBQwQms.Id2JOeb6..mi8UQQka8dyWNkh0WqmAm/hN0AQX9zW", first_name: "John", id: 1, inserted_at: ~N[2019-01-02 08:36:35.417355], is_admin: false, last_name: "Doe", owned_board: #Ecto.Association.NotLoaded<association :owned_board is not loaded>, password: nil, updated_at: ~N[2019-01-02 08:36:35.426004], user_board: #Ecto.Association.NotLoaded<association :user_board is not loaded>}, :config, [])
        (guardian) lib/guardian.ex:776: Guardian.token_module/1
        (guardian) lib/guardian.ex:576: Guardian.encode_and_sign/4
        (imcon) lib/imcon_web/controllers/api/v1/session_controller.ex:9: ImconWeb.SessionController.create/2

The configuration is such here.

[
  {:phoenix, "~> 1.4.0"},
  {:phoenix_pubsub, "~> 1.1.1"},
  {:phoenix_ecto, ">= 3.2.0 and < 3.5.0"},
  {:postgrex, ">= 0.0.0"},
  {:poison, ">= 0.0.0"},
  {:phoenix_html, "~> 2.12.0"},
  {:phoenix_live_reload, "~> 1.2.0", only: :dev},
  {:gettext, "~> 0.16.1"},
  {:cowboy, "~> 2.6.0"},
  {:plug_cowboy, "~> 2.0.0"},
  {:comeonin, "~> 4.1.1"},
  {:bcrypt_elixir, "~> 1.0.9"},
  {:guardian, "~> 1.1.1"},
  {:credo, "~> 0.10.2", only: [:dev, :test]},
  {:ex_machina, "~> 2.2.2"},
  {:exactor, "~> 2.2.4"},
  {:hound, "~> 1.0.2"},
  {:mix_test_watch, "~> 0.9.0", only: :dev},
  {:poolboy, "~> 1.5.1"}
]

Showing Posts 1 to 10

van-mronov

van-mronov

As error message said the problem occurs in create action not in index.

NobbZ

NobbZ

Which version of ecto is effectively used, please show us the appropriate line of mix.lock. If it is >= 3.0 please tell us about ecto_sql as well.

PavelZX

PavelZX OP

“ecto”: {:hex, :ecto, “2.2.11”, “4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c”, [:mix], [{:db_connection, “~> 1.1”, [hex: :db_connection, repo: “hexpm”, optional: true]}, {:decimal, “~> 1.2”, [hex: :decimal, repo: “hexpm”, optional: false]}, {:mariaex, “~> 0.8.0”, [hex: :mariaex, repo: “hexpm”, optional: true]}, {:poison, “~> 2.2 or ~> 3.0”, [hex: :poison, repo: “hexpm”, optional: true]}, {:poolboy, “~> 1.5”, [hex: :poolboy, repo: “hexpm”, optional: false]}, {:postgrex, “~> 0.13.0”, [hex: :postgrex, repo: “hexpm”, optional: true]}, {:sbroker, “~> 1.0”, [hex: :sbroker, repo: “hexpm”, optional: true]}], “hexpm”},
“ex_machina”: {:hex, :ex_machina, “2.2.2”, “d84217a6fb7840ff771d2561b8aa6d74a0d8968e4b10ecc0d7e9890dc8fb1c6a”, [:mix], [{:ecto, “~> 2.2 or ~> 3.0”, [hex: :ecto, repo: “hexpm”, optional: true]}, {:ecto_sql, “~> 3.0”, [hex: :ecto_sql, repo: “hexpm”, optional: true]}], “hexpm”},

ecto_sql not installed, as I understand it.

PavelZX

PavelZX OP

[
{:phoenix, “~> 1.4.0”},
{:phoenix_pubsub, “~> 1.1.1”},
{:phoenix_ecto, “~> 4.0.0”},
{:ecto, “>= 3.0.6”},
{:ecto_sql, “~> 3.0.4”},
{:postgrex, “>= 0.0.0”},
{:poison, “>= 0.0.0”},
{:phoenix_html, “~> 2.12.0”},
{:phoenix_live_reload, “~> 1.2.0”, only: :dev},
{:gettext, “~> 0.16.1”},
{:cowboy, “~> 2.6.0”},
{:plug_cowboy, “~> 2.0.0”},
{:comeonin, “~> 4.1.1”},
{:bcrypt_elixir, “~> 1.0.9”},
{:guardian, “~> 1.1.1”},
{:credo, “~> 0.10.2”, only: [:dev, :test]},
{:ex_machina, “~> 2.2.2”},
{:exactor, “~> 2.2.4”},
{:hound, “~> 1.0.2”},
{:mix_test_watch, “~> 0.9.0”, only: :dev},
{:poolboy, “~> 1.5.1”}
]
end

“db_connection”: {:hex, :db_connection, “2.0.3”, “b4e8aa43c100e16f122ccd6798cd51c48c79fd391c39d411f42b3cd765daccb0”, [:mix], [{:connection, “~> 1.0.2”, [hex: :connection, repo: “hexpm”, optional: false]}], “hexpm”},
“decimal”: {:hex, :decimal, “1.6.0”, “bfd84d90ff966e1f5d4370bdd3943432d8f65f07d3bab48001aebd7030590dcc”, [:mix], , “hexpm”},
“ecto”: {:hex, :ecto, “3.0.6”, “d33ab5b3f7553a41507d4b0ad5bf192d533119c4ad08f3a5d63d85aa12117dc9”, [:mix], [{:decimal, “~> 1.6”, [hex: :decimal, repo: “hexpm”, optional: false]}, {:jason, “~> 1.0”, [hex: :jason, repo: “hexpm”, optional: true]}, {:poison, “~> 2.2 or ~> 3.0”, [hex: :poison, repo: “hexpm”, optional: true]}], “hexpm”},
“ecto_sql”: {:hex, :ecto_sql, “3.0.4”, “e7a0feb0b2484b90981c56d5cd03c52122c1c31ded0b95ed213b7c5c07ae6737”, [:mix], [{:db_connection, “~> 2.0”, [hex: :db_connection, repo: “hexpm”, optional: false]}, {:ecto, “~> 3.0.6”, [hex: :ecto, repo: “hexpm”, optional: false]}, {:mariaex, “~> 0.9.1”, [hex: :mariaex, repo: “hexpm”, optional: true]}, {:postgrex, “~> 0.14.0”, [hex: :postgrex, repo: “hexpm”, optional: true]}, {:telemetry, “~> 0.3.0”, [hex: :telemetry, repo: “hexpm”, optional: false]}], “hexpm”},
“elixir_make”: {:hex, :elixir_make, “0.4.2”, “332c649d08c18bc1ecc73b1befc68c647136de4f340b548844efc796405743bf”, [:mix], , “hexpm”},
“ex_machina”: {:hex, :ex_machina, “2.2.2”, “d84217a6fb7840ff771d2561b8aa6d74a0d8968e4b10ecc0d7e9890dc8fb1c6a”, [:mix], [{:ecto, “~> 2.2 or ~> 3.0”, [hex: :ecto, repo: “hexpm”, optional: true]}, {:ecto_sql, “~> 3.0”, [hex: :ecto_sql, repo: “hexpm”, optional: true]}], “hexpm”},

Errors, in the end, remained the same.

PavelZX

PavelZX OP

What else ideas can be how to overcome this error?

PavelZX

PavelZX OP

** (ArgumentError) argument error
:erlang.apply(%Imcon.Auth.User{meta: #Ecto.Schema.Metadata<:loaded, “user”>, board: #Ecto.Association.NotLoaded, email: “john@phoenix-trello.com”, encrypted_password: “$2b$12$nn1jeBQwQms.Id2JOeb6..mi8UQQka8dyWNkh0WqmAm/hN0AQX9zW”, first_name: “John”, id: 1, inserted_at: ~N[2019-01-02 08:36:35], is_admin: false, last_name: “Doe”, owned_board: #Ecto.Association.NotLoaded, password: nil, updated_at: ~N[2019-01-02 08:36:35], user_board: #Ecto.Association.NotLoaded}, :config, )

Судя, по сообщению ошибки, не получается загрузить ассоциацию второго уровня. Вот схемы, я только добавил поле is_admin.

Judging by the error message, I can’t download the second level association. Here are the schemes, I just added the is_admin field.

  schema "user" do
    
    field :first_name, :string
    field :last_name, :string
    field :email, :string
    field :is_admin, :boolean, default: false
    field :encrypted_password, :string
    field :password, :string, virtual: true

    has_many :owned_board, Board
    has_many :user_board, UserBoard
    has_many :board, through: [:user_board, :board]

Maybe there is a problem somewhere?

  schema "board" do
    field :name, :string, null: false
    field :slug, :string, null: false

    belongs_to :user, User
    has_many :list, List
    has_many :card, through: [:list, :card]
    has_many :user_board, UserBoard
    has_many :member, through: [:user_board, :user]

Here I did not change anything at all yet.

  schema "user_board" do
    belongs_to :user, User
    belongs_to :board, Board
van-mronov

van-mronov

Ecto doesn’t load associations by default. So this is an expected behaviour.

Error message says that you try to call :erlang.apply/3 with your user model as a first arg, but it should be a module name. That’s why ArgumentError is raised.

Again, according to your first post, error occurs inside the guardian application code after something in session_controller, line 9. So, it would be helpful to look at session_controller create action.

PavelZX

PavelZX OP

If Erlang himself swears, then, is the error still covered in the communication modules with the database?

  defmodule ImconWeb.SessionController do
      use ImconWeb, :controller

  plug :scrub_params, "session" when action in [:create]

  def create(conn, %{"session" => session_params}) do
    case Imcon.Auth.authenticate(session_params) do
      {:ok, user} ->
        {:ok, jwt, _full_claims} = user |> Guardian.encode_and_sign(:token)

        conn
        |> put_status(:created)
        |> render("show.json", jwt: jwt, user: user)

      :error ->
        conn
        |> put_status(:unprocessable_entity)
        |> render("error.json")
    end
  end

  def delete(conn, _) do
    {:ok, claims} = Guardian.Plug.current_claims(conn)

    conn
    |> Guardian.Plug.current_token
    |> Guardian.revoke(claims)

    conn
    |> render("delete.json")
  end


  def unauthenticated(conn, _params) do
    conn
    |> put_status(:forbidden)
    |> render(ImconWeb.SessionView, "forbidden.json", error: "Not Authenticated")
  end

end

Based on various examples, I brought the authentication to a separate new context. I want to enter roles, for users, groups (teams), adding this context.

defmodule Imcon.Auth do

  import Ecto.Changeset
  import Plug.Conn
  
  alias Comeonin.Bcrypt

  alias Imcon.Repo
  alias Imcon.Auth.User

    # ... User

  def get_user(id), do: Repo.get(User, id)

  def fetch_assoc(%User{} = user, assoc \\ [:board, :user_board, :owned_board]) do
    Repo.preload(user, assoc)
  end

  @required_fields ~w(first_name last_name email password)
  @optional_fields ~w(encrypted_password)

  def create_user(%User{} = user, attrs) do
    user
    |> cast(attrs, @required_fields, @optional_fields)
    |> validate_format(:email, ~r/@/)
    |> validate_length(:password, min: 5)
    |> validate_confirmation(:password, message: "Password does not match")
    |> unique_constraint(:email, message: "Email already taken")
    |> generate_encrypted_password
  end

  def update_user(%User{} = user, attrs) do
    user
    |> cast(attrs, [:first_name, :last_name, :email], [:password])
    |> validate_required([:first_name, :email])
    |> generate_encrypted_password
    |> unique_constraint(:email)
  end

  defp generate_encrypted_password(current_changeset) do
    case current_changeset do
      %Ecto.Changeset{valid?: true, changes: %{password: password}} ->
        put_change(current_changeset, :encrypted_password, Comeonin.Bcrypt.hashpwsalt(password))
      _ ->
        current_changeset
    end
  end

  def load_current_user(conn, _) do
    conn
    |> assign(:current_user, Guardian.Plug.current_resource(conn))
    |> put_user_token(Guardian.Plug.current_resource(conn))
  end

  defp put_user_token(conn, user) do
    token = Phoenix.Token.sign(conn, "user socket", user.id)

    conn
    |> assign(:user_token, token)
  end

  def authenticate(%{"email" => email, "password" => password}) do
    user = Repo.get_by(User, email: String.downcase(email))

    case check_password(user, password) do
      true -> {:ok, user}
      _ -> :error
    end
  end

  defp check_password(user, password) do
    case user do
      nil -> Bcrypt.dummy_checkpw()
      _ -> Bcrypt.checkpw(password, user.encrypted_password)
    end
  end

end
PavelZX

PavelZX OP

Most likely I have copied and pasted something wrong. It is necessary to open a new topic on authentication.

** (exit) an exception was raised:
** (CaseClauseError) no case clause matching: true
(imcon) lib/imcon_web/controllers/api/v1/session_controller.ex:7: ImconWeb.SessionController.create/2
(imcon) lib/imcon_web/controllers/api/v1/session_controller.ex:1: ImconWeb.SessionController.action/2
(imcon) lib/imcon_web/controllers/api/v1/session_controller.ex:1: ImconWeb.SessionController.phoenix_controller_pipeline/2
(imcon) lib/imcon_web/endpoint.ex:1: ImconWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:275: Phoenix.Router.call/1
(imcon) lib/imcon_web/endpoint.ex:1: ImconWeb.Endpoint.plug_builder_call/2
(imcon) lib/plug/debugger.ex:122: ImconWeb.Endpoint.“call (overridable 3)”/2
(imcon) lib/imcon_web/endpoint.ex:1: ImconWeb.Endpoint.call/2
(phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:34: Phoenix.Endpoint.Cowboy2Handler.init/2
(cowboy) /opt/imcon/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
(cowboy) /opt/imcon/deps/cowboy/src/cowboy_stream_h.erl:296: :cowboy_stream_h.execute/3
(cowboy) /opt/imcon/deps/cowboy/src/cowboy_stream_h.erl:274: :cowboy_stream_h.request_process/3
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

defmodule ImconWeb.SessionController do
  use ImconWeb, :controller

  plug :scrub_params, "session" when action in [:create]

  def create(conn, %{"session" => %{"email" => email, "password" => password}}) do
    case Imcon.Auth.authenticate(email, password) do
      {:ok, user} ->
        {:ok, jwt, _full_claims} = user |> Guardian.encode_and_sign(:token)

        conn
        |> put_status(:created)
        |> render("show.json", jwt: jwt, user: user)

      :error ->
        conn
        |> put_status(:unprocessable_entity)
        |> render("error.json")
    end
  end

  def delete(conn, _) do
    {:ok, claims} = Guardian.Plug.current_claims(conn)

    conn
    |> Guardian.Plug.current_token
    |> Guardian.revoke(claims)

    conn
    |> render("delete.json")
  end
  
  def unauthenticated(conn, _params) do
    conn
    |> put_status(:forbidden)
    |> render(ImconWeb.SessionView, "forbidden.json", error: "Not Authenticated")
  end

end

Fragment from file auth.ex

  def authenticate(email, encrypted_password) do
    query = Ecto.Query.from(u in User, where: u.email == ^email)
    |> limit(1)
    Repo.one(query)
    |> check_password(encrypted_password)
  end

  defp check_password(user, password) do
    case user do
      nil -> Bcrypt.dummy_checkpw()
      _ -> Bcrypt.checkpw(password, user.encrypted_password)
    end
  end
van-mronov

van-mronov

The issue from the first post occurs in this line:

According to guardian docs the first argument is the module implementing actual encoding in callbacks, but you pass user struct as first arg.

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews