Here's a quick Plug for a Phoenix project that allows you to quickly and easily set template variables (assigns) in either a Pipeline or for all actions in a controller. I used this recently as a way to set a variable, admin: true , for all of my controllers under an /admin scope. I also used it to set a subsection variable for the different controllers that make up the different parts of the site so that my Layout template could mark which section of the site the user was currently on in the site navigation header.

Update 10/14/15: I went ahead and published this as a self-contained hex package, if nothing else than as an exercise in publishing things. It's available on hex.pm. Note that I renamed it to Plug.Assign to better match existing Plug names.

The Plug

The Plug itself is very straightforward since we're able to exploit the fact that Phoenix just uses Plug's assigns map that is part of the Plug.Conn struct as the holding place for template context variables. Thus we can assign our own variables as part of the Plug stack before the Controller action (which itself is just a plug) even executes. So our first step is going to be creating the plug.

As an interface, our plug will accept a map of key/value pairs, exactly like the render/3 function in a Controller/View. So as an example, it will look like:

plug Plugs.Assigns , foo : "This is foo" , bar : true , baz : 5

I decided to put it in lib/plugs and named the source file assigns.ex so that my module name will be Plugs.Assigns . This way I can easily copy this plug to other projects. It could even be packaged up as a Hex package and installed as a dependency. So lib/plugs/assigns.ex will look like:

defmodule Plugs.Assigns do import Plug.Conn def init ( assigns ), do : assigns def call ( conn , assigns ) do Enum . reduce assigns , conn , fn { k , v }, conn -> Plug.Conn . assign ( conn , k , v ) end end end

If you're not familiar with the Plug spec, two functions are required, init/1 and call/2 . We don't need to do anything with the map at initialization time, so our init/1 function just returns it. However, for each request, our call/2 function will take the assigns map and add it to the conn . This could possibly be written more efficiently by directly manipulating the assigns map in the Plug.Conn struct conn , but I opted to use the interface so that it uses the public Plug.Conn.assign function, making it more compatible with possible future changes to Plug.

Using in a Pipeline

Let's say you want to assign a variable admin to either true if the current request is being routed to an /admin scope. For example, you have something like this defined in your routers.ex :

defmodule Blog.Router do use Blog.Web , :router pipeline :browser do plug :accepts , [ "html" ] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers end scope "/" , Blog do pipe_through :browser # Use the default browser stack get "/" , PageController , :index get "/post/:post_id" , PageController , :post end scope "/admin" , Blog.Admin do pipe_through :browser # Use the default browser stack resources "/posts" , PostController resources "/users" , UserController end end

Now let's say you would like to modify your layout/app.html.eex template so that it has "Admin: " prefixed to the page title, as an example.

<title> <%= if assigns [ :admin ] , do : "Admin: " %> My Blog! </title>

We would do this by defining a new pipeline in router.ex , and call it :admin :

pipeline :admin do plug Plugs.Assigns , %{ admin : true } end

And then we can modify our /admin scope to use it.

scope "/admin" , Blog.Admin do pipe_through [ :browser , :admin ] # Use admin stack as well resources "/posts" , PostController resources "/users" , UserController end

Now all requests to any controller under /admin will include the variable admin: true .

Using it to assign a variable for all Controllers

Another way to use this would be to set a variable for all action functions in a Controller. To continue our example, in our web/controllers/admin/post_controller.ex file, we could just add a plug call to our custom Plug near the top.

defmodule Blog.Admin.PostController do use Blog.Web , :controller alias Blog.Post plug :scrub_params , "post" when action in [ :create , :update ] plug Plugs.Assigns , subsection : :posts ... end

Our corresponding template could check if the subsection variable is set to something specific to enable a visual indication of what subsection the user is currently in.

<li class= " <%= if assigns [ :subsection ] == :posts do "active" end %> " > <a href= " <%= post_path ( @conn , :index ) %> " > Posts </a> </li>

If you wanted to limit the plug to only certain actions, this could be done by adding a when clause. However, do note that when you do that, the map of assigns will no longer be the last predicate, and so you need to wrap it in a map operator, %{} .

plug Plugs.Assigns , %{ subsection : :posts } when action in [ :index , :show ]

Now the subsection variable will only be set to :posts when the user is calling the :index and :show actions.

So there's an example of how powerful the Plug interface is, and how it allows you to add so much functionality with almost no code.