martijn

martijn

Am I doing this right? Pattern matching in controller methods

In my first Phoenix app, I have an action which serves an XML phonebook to a certain SIP handset. The handset has two ways of calling this action:

/gigaset?reqsrc=user&ln=foo   # Search for a contact with the name 'foo'
/gigaset?reqsrc=auto&hm=12345 # Search for a contact with caller ID 12345

Since both have different queries I decided to pattern match based on the reqsrc parameter. But both action have some shared logic as well, so I put that in a separate method with the same name but different arity to apply limit and offset and render the view/template. It works, but is this the right way of doing things?

  # User quering phonebook from Gigaset base
  def gigaset(conn, params = %{"reqsrc" => "user"}) do
    name = String.replace(params["ln"], "*", "%")
    query = from e in Entry, where: ilike(e.name, ^name)

    gigaset conn, query, params
  end

  # Caller ID from Gigaset base
  def gigaset(conn, params = %{"reqsrc" => "auto"}) do
    number = params["hm"]
    query = from e in Entry, where: e.work == ^number or e.home == ^number or e.mobile == ^number

    gigaset conn, query
  end

  # Finish query, render output
  def gigaset(conn, query, params) do
    limit = String.to_integer(params["count"])
    offset = String.to_integer(params["first"]) - 1

    query = from e in query, limit: ^limit, offset: ^offset
    entries = Repo.all(query)

    render conn, entries: entries
  end

I know the difference in the query is trivial, but imagine they would be vastly different. Does it make sense to do it like this?

Most Liked

sashaafm

sashaafm

I don’t think there’s any problem in using pattern matching in controller methods. I’ve done this in one of my projects myself and it works great:

  def insert_attachment(conn, %{"ticket_message" => ticket_message,
                                "ticket_id"      => ticket_id}) do

    ticket = Repo.get(Ticket, ticket_id)
    upload = Map.get(ticket_message, "file")
    TicketAttachmentController.insert(conn, ticket, upload)
  end

  def insert_attachment(conn, %{"ticket_id"      => ticket_id}) do

    conn
    |> put_flash(:error, "No file was selected.")
    |> redirect(to: ticket_path(conn, :show, ticket_id))
  end
NobbZ

NobbZ

Your match does only “fire” when you have all the parameters "reqsrc", "count", and "first" available. In the requested “path” /gigaset?reqsrc=auto" there is only "reqsrc" available, so you need to add another clause after your current one, which needs to be like this:

def gigaset(conn, params = %{"reqsrc" => "auto"}), do: :stuff
martijn

martijn

Wait.. after testing it again it seems to not work as expected :persevere:

Requesting /gigaset?reqsrc=auto yields a ‘no matching action clause to process request’ error on the definition of the first method. Is there a way to do this, at all?

I ended up rewriting into this long method (with some more changes):

  def gigaset(conn, params = %{ "reqsrc" => reqsrc, "count" => limit, "first" => offset }) do
    query = case reqsrc do
      # User quering phonebook from Gigaset base
      "user" ->
        name = String.replace(params["ln"], "*", "%")
        from e in Entry, where: ilike(e.name, ^name)

      # Caller ID from Gigaset base
      "auto" ->
        number = params["hm"]
        from e in Entry, where: e.work == ^number or e.home == ^number or e.mobile == ^number
    end

    # Total before pagination
    total = Repo.one(from e in query, select: count(e.id))

    # Paginated entries
    offset = String.to_integer(offset) - 1
    query = from e in query, limit: ^limit, offset: ^offset
    entries = Repo.all(query)

    render conn, entries: entries, total: total, offset: offset
  end

All feedback is welcome! I realise some of this belongs in the model probably.

Where Next?

Popular in Questions Top

fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> somethi...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
hariharasudhan94
Lets say i have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => "XXX...
New

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement