However, the following code is different and uses a pattern match to get the “user” key data.
def create(conn, %{"user" => user_params}) do
IO.inspect user_params
# pattern matches on "user" and returns the following:
# "user" => %{
# "email" => "adada@aad.com",
# "password_hash" => "asdasdasd",
# "username" => "adadadasd"
# }
end
Can someone explain how this happens?
If I do the following it does not work (nor would I expect it to):
defmodule App do
def create(params) do
IO.inspect(params)
end
end
some_params = %{
"_csrf_token" => "GwUOLhQYeUMnBXsyITsEUQYYAxkVAAAAu7gVbIN7b6BpxbugToahew==",
"_utf8" => "âś“",
"user" => %{
"email" => "adada@aad.com",
"password_hash" => "asdasdasd",
"username" => "adadadasd"
}
}
App.create(%{"user" => some_params}) # Does not give me the user map
Talking in high level abstraction, your controller function is pattern matched wit the incoming request, there you say to match “a map, containing a user key with some value”. Basically if in your request does not have this user key it will get rejected making the controller throw an error, because no function matched.
In your example the map that corresponds to the incoming request is your “some_params” because inside it have a user key
Just to put it into simple sentences here, and lets remove conn for a second.
Given an input like :
%{
"_csrf_token" => "GwUOLhQYeUMnBXsyITsEUQYYAxkVAAAAu7gVbIN7b6BpxbugToahew==",
"_utf8" => "âś“",
"user" => %{
"email" => "adada@aad.com",
"password_hash" => "asdasdasd",
"username" => "adadadasd"
}
}
# I will accept the input and bind it to `user_params`
def create(user_params) do
# I will accept the input if it has a key named `user`
# and then bind the value of `user` to `user_params`
def create(%{"user" => user_params}) do
# I will accept the input if it has a key named `user`
# and then bind the value of `user` to `user_params`
# and I will bind the whole value to `some_params`
def create(%{"user" => user_params} = some_params) do
So all three functions will accept the input but
The first function will just bind the value to user_params
The second function will extract the "user" key from the input and give you the value of "user"
In this case a map with the email, password_hash and username
The following example made it clear what is happening.
Explicit pattern match example
defmodule App do
def create(data) do
%{"users" => data} = data # Explicit pattern match
IO.inspect(data)
end
end
data = %{
"users" => "some users and stuff",
"other_junk" => "blah ...junk"
}
App.create(data)
Less Explicit Example
defmodule App do
def create(%{"users" => data}) do
IO.inspect(data)
end
end
data = %{
"users" => "some users and stuff",
"other_junk" => "blah ...junk"
}
App.create(data) # %{"users" => data} = data
When I was originally looking at the code I thought there was some weird behavior so that when a map is set as a function parameter then any arguments passed into that slot as an argument are not matched on the map but instead are passed into the map…or something