0

I'm using {:guardian, "~> 1.0"} for my project to generate a token but it's giving me an error.

Here's a code for my guardian file

defmodule Dailyploy.Guardian do
  use Guardian, otp_app: :dailyploy

  def subject_for_token(user, _claims) do
    sub = to_string(user.id)
    {:ok, sub}
  end

  def subject_for_token(_, _) do
    {:error, :reason_for_error}
  end

  def resource_from_claims(claims) do
    id = claims["sub"]
    resource = Dailyploy.Accounts.get_user!(id)
    {:ok,  resource}
  end

  def resource_from_claims(_claims) do
    {:error, :reason_for_error}
  end
end

It's showing me an error that subject_for_token. This clause cannot match because a previous clause at line 4 always matchesElixir

Can someone please explain why it is not working?

donjuedo
  • 2,475
  • 18
  • 28

2 Answers2

1

The compiler is complaining because your two definitions of subject_for_token are identical, they both expect the exact same arguments.

To fix this, make it explicit that you want to receive a User struct in the first definition:

  def subject_for_token(%User{id: id}, _claims) do
    {:ok, to_string(id)}
  end

  def subject_for_token(_, _) do
    {:error, :reason_for_error}
  end

The same can be said about resource_from_claims; both functions will match the exact same arguments. This too can be fixed:

  def resource_from_claims(%{"sub" => sub}) do
    resource = Dailyploy.Accounts.get_user!(sub)
    {:ok, resource}
  end

  def resource_from_claims(_claims) do
    {:error, :reason_for_error}
  end
zwippie
  • 15,050
  • 3
  • 39
  • 54
  • { "resource": "/home/shweta/dailyploy/lib/guardian.ex", , "message": "** (CompileError) lib/guardian.ex:4: User.__struct__/0 is undefined, cannot expand struct User\n lib/guardian.ex:4: (module)\n", } – Siddhant Singh Jul 12 '19 at 10:07
  • I assumed you have a `User` schema somewhere in your application that you want to use here. If so, change it to the exact User module you are using, like `Dailyploy.Accounts.User`. – zwippie Jul 12 '19 at 10:22
  • *change it to the exact User module you are using, like Dailyploy.Accounts.User*-- Or, include the line: `alias Dailyploy.Accounts.User` which will make `%User{}` equivalent to `%Dailyploy.Accounts.User{}` – 7stud Jul 12 '19 at 18:00
0

Can someone please explain it why is that not working?

When you call a function, elixir starts with the first function clause in the definition and tries to match the arguments specified in the function call to the parameters in the function definition. If there's no match, elixir then tries the next function clause. When a match is found, the corresponding function body executes. If none of the function clauses match, then you get a function_clause error.

Let's go through an example. If you write:

def go({1, 2}, :cat) do
   IO.puts "I must have matched the function call."
end

then you can call that function like this:

iex(2)> A.go({1, 2}, :cat)
I must have matched the function call.
:ok

But, if you try:

ex(3)> A.go("hello", 10)
** (FunctionClauseError) no function clause matching in A.go/2    

    The following arguments were given to A.go/2:

        # 1
        "hello"

        # 2
        10

    a.ex:2: A.go/2

You get a function clause error because no function clause for the definition of go() matches the function call:

  function call:     A.go("hello", 10)
                            |       |
            {1,2} = "hello  |       | :cat = 10
                            V       V
  function def:    def go({1, 2}, :cat) do

The only argument in the go() function call that can match the tuple {1, 2} in the function definition is the tuple {1, 2}, and the only argument in the function call that can match the atom :cat in the function definition is the atom :cat.

However, variables in a function definition match ANYTHING. Some examples of legal variable names are: x, y, _x and _. So, if you define go() like this:

  def go(_x, _y) do
    IO.puts "I must have matched the function call."
  end

then both function calls will match:

iex(3)> c "a.ex"          
warning: redefining module A (current version defined in memory)
  a.ex:1
[A]

iex(4)> A.go("hello", 10)
I must have matched the function call.
:ok

iex(5)> A.go({1, 2}, :cat)
I must have matched the function call.
:ok

If you add a second function clause to the go() definition:

  def go(_x, _y) do
    IO.puts "I must have matched the function call."
  end
  def go(_, _) do
    IO.puts "I will never match"
  end

the first function clause will still match any two arguments, and because that's the case, the second function clause will never execute--so the compiler gives you a warning, which is equivalent to:

Wtf? Why did you scribble all that junk in the second function clause when it will never match and therefore never execute?! Get a grip!

Things get a little trickier when you do pattern matching in the function definition, for instance:

def go(%{a: val}=map, x) do

See here for how that works.

7stud
  • 46,922
  • 14
  • 101
  • 127