Writing a Blog Engine in Phoenix and Elixir: Part 11, better UI

Brandon Richey
Mar 28, 2016 · 15 min read

Latest Update: 08/02/2016

Wow, monthlyhipstercrate.com really paid off this month!

Previous Post in this series

Current Versions

  • Elixir: v1.3.1
  • Phoenix: v1.2.0
  • Ecto: v2.0.2

Where We Left Off

When we left off last, we had just finished writing tests for everything we had related to channels. This tutorial again is going to be significantly less Elixir/Phoenix-heavy and just showcase how to integrate some external stuff into our Phoenix application. Generally, Phoenix starts you off with a very, very basic version of Twitter Bootstrap that has been tweaked to be very Phoenix-specific, so we’re going to go off the rails a little bit and swap out to a different framework (and utilize SASS).

Disclaimer: I am really, really not a designer. I may do things that are icky or otherwise ill-advised, and if you notice them, please feel free to point them out or change them for yourself, but consider yourself warned.

Why Foundation?

I won’t attempt to jump into the Bootstrap/Foundation discussion or argument since web design is really not my focus anymore. Instead, I’m choosing Foundation because it looks a little more interesting than your standard programmer-designed Bootstrap site, and I find it to have a little less boilerplate stuff that I have to do in Bootstrap 3. I’ve not used Bootstrap 4, so I can’t really speak to how good that one is yet. Besides, not a lot of people have used Foundation in comparison, so let’s have some fun with it!

Installing Zurb Foundation 6

NOTE: Please note that we’re installing a very specific version of jquery here (v2.2.4) to avoid issues between jquery and foundation that may appear. For more information. For more information, check out https://medium.com/@brettwise/as-of-the-posting-of-this-comment-foundation-chokes-on-jquery-version-3-the-default-installed-with-710ee277be00#.uwn3dmaz2 (Thanks a lot, Brett Wise!)

We’ll also need to edit brunch-config.js to accommodate the new changes that pull Foundation into Brunch (namely, including the sass load directories and sass module config and the inclusion of jquery as a global for NPM):

Next, since we’re going to be using SASS for this project with Foundation, we’ll want to create a folder for our sass files. Create web/static/scss and then we’re going to add three files to the directory:

In web/static/scss/application.scss:

In web/static/scss/_settings.scss:

Just download this file and place the contents in the file above (the file is huge so I don’t want to embed it here): Download from here

In web/static/scss/_custom.scss:

You’ll also want to download https://raw.githubusercontent.com/Diamond/pxblog/new_ui/web/static/assets/images/computer-bg.png and throw the file into web/static/assets/images/computer-bg.png since our custom scss file uses that as the background.

Installing Foundation Icons/Fonts

Also, you’ll want to download the Icon Fonts for Foundation. To do this, you’ll need to follow these steps:

  1. Download http://zurb.com/playground/uploads/upload/upload/288/foundation-icons.zip
  2. Unzip the file contents
  3. Copy the following files to web/static/assets/fonts: foundation-icons.eot, foundation-icons.svg, foundation-icons.ttf, foundation-icons.woff
  4. Copy the following file to web/static/css: foundation-icons.css
  5. Finally, modify the foundation-icons.css file so that the urls for each of the fonts respects Phoenix’s asset paths:

Now Foundation Icons should be installed as well!

Removing The Phoenix Default Styles

Open up web/static/css/phoenix.css and delete the whole thing! We may not use this later at all, but it’s good to have if you need to do something in standard CSS instead of SASS for some reason.

Refactoring Our Current User Approach

One of the things we want to do before we continue is take a refactoring approach to some of the code we’ve been writing. For example, the way we handle the current user is a little wonky, requiring us to import some code over and over again. Let’s make everything related to current user more reusable for us. We’ll start by creating a new plug that we’ll insert into web/controllers/current_user_plug.ex:

What is this doing? Well, we start off by importing Plug.Conn into our module (so that we easily access the assign/get_session functions). We then declare our init function that takes in a default variable and immediately returns it back out. The meat of our plug lives in the call function, however. Any plug we write needs to implement both an init and call function, and our call function needs to accept the conn and optionally some options and return out a conn as well (modified or not).

If the current_user is able to get fetched out of the current session, then we turn around and throw that in the assigns so that anything that has access to the conn will also have access to the current user! If we can’t fetch it out, then we’ll just return an unmodified conn! Next, to implement our current_user plug globally, we’ll open up web/router.ex and insert it into our standard browser pipeline:

And that’s it! Now in our layouts and templates, when we need to access the current logged-in user, we can just access @conn.assigns[:current_user]. Nice!

Refactoring Our Application Layout

We’re going to refactor our current application layout to make it easier for us to modify some of the shared parts of our layout that we’ll be reusing. We’ll start by our entire head section (everything between the <head> tags). Create web/templates/layout/head.html.eex and copy/paste our current head tag into that section:

For the most part we just cut/pasted the head tag and contents into a new file but we’re also going to refactor the current user bit and add information for our description/author/title tags. Instead of our previous system of using a helper function inside of LayoutView, we now check if current_user is set in our assigns, and if it is, use the current user as our setting for the meta tag! Next, we’ll refactor our the navigation top bar into its own template. Create web/templates/layout/navigation.html.eex:

This is the first big of code that’s really using Foundation in a major way. We start off using Foundation’s “top-bar” class and various menus and left/right pulls. We rip out the old Phoenix logo and navigation bar completely and just use some simple text for our new logo. We’ll just call this a “Phoenix Tech Blog” for now for sake of simplicity. Otherwise we’re just building out some simple HTML with a couple of Foundation’s built-in styles/components. Again, any place that we were referencing the old style of fetching the current user we replace with the new style that takes advantage of our new Plug.

A Quick Rundown Of Foundation Classes Introduced

In the last example, we started using a few Foundation classes that I’ll just briefly explain here:

  1. top-bar is just a top navigation bar, as you’d expect. (Docs)
  2. top-bar-left is a left-pulling subsection of our top-bar. Similarly, top-bar-right is a right-pulling subsection.
  3. menu tells Foundation that we’re expecting this to be a menu of links. (Docs)
  4. button tells Foundation to use default Button styling on the link or button tag. (Docs)
  5. alert tells Foundation which color to use for the button. (Docs)

Continuing Our Refactor Of The Application Layout

Next, we’ll tackle the alerts, since that is also pretty frequently reused code. Let’s create web/templates/layout/alerts.html.eex:

We have to modify everything a little more heavily here, since Phoenix by default makes certain expectations about CSS classes being used and their intentions. These changes make the alert code and styling a little more platform-agnostic.

We see if we can fetch the flash out of the conn, and if we can, then we display the flash div appropriately. If not, nothing will get displayed. This WILL include a blank div, though (which won’t affect our layout, just the source output).

A Quick Rundown Of Foundation Classes Introduced

  1. row tells Foundation that it is a container for its grid system. (Docs)
  2. callout creates a standard Flash div container look. (Docs)
  3. success provides a nice light green style for a successful callout. (Docs)
  4. alert provides a nice light red style for error messages. (Docs)

The Final Refactoring Of Our Application Layout

We have two partials remaining that we want to refactor/redesign. The first is our main content rendering portion. We’ll wrap this inside of a div with the classes of “row” and “content”:

We’ll also create a new template to store the standard JavaScript includes at the bottom. Create web/templates/layout/script.html.eex:

The major new addition here is the closure that includes a call to the foundation() function on the document object. This is required for Foundation’s built-in javascript helpers!

Changing Our Application Layout To Use Our Partials

Finally, we’ll take a look at our application layout after we’ve refactored out all of the shared content. Let’s modify web/templates/layout/app.html.eex:

As you can see, our application layout file is really small and really reusable now! This is going to be VERY handy as we start to dive into creating a new layout that will be used for the index action on our PageController (which will become our splash page).

Creating A New Layout

Next, we’re going to create a new layout that we’ll call splash. Create web/templates/layout/splash.html.eex:

There’s a lot going on here, but nearly all of it is just content with a little bit of styling here and there! Let’s walk through some of the other Foundation classes we’re using here:

  1. expanded when attached to a row makes the row take up the whole width of the screen (Docs)
  2. text-center is exactly what it sounds like: centered text. Similarly, text-left and text-right align the text to the left and right, respectively (Docs)
  3. fi-comments, fi-pencil, fi-like are all Foundation icons (Docs)
  4. columns tells Foundation that we’ll be setting up separate columns using their grid system (Docs)
  5. medium-12, large-4 are examples of using the responsive sizing models for grid systems. On medium devices it will take up 12 columns, and on large devices it will take up 4 columns. (You will also see examples using small-N where N is some number between 1 and 12) (Docs)

Finally, let’s tell Phoenix that we’re going to use the new splash layout only for our PageController. Open up web/controllers/page_controller.ex and at the top, add the following line (after our use statement):

Creating A Non-Logged-In Posts Display

We should also create a way for users to be able to view the last N number of posts if they’re not logged in, since there’s no point having a fancy blog if no one can read any of the posts! First, we’ll open up web/router.ex and add an index-only resource for posts:

And then we’ll open up web/controllers/post_controller.ex and modify our index function and add a new pattern-matched index function, but first we’ll start with a modification to our “assign_user” plug at the top of the file:

And then our index function modifications:

The first call looks for the existence of “user_id” in our params; that’s how we know we’re fetching the specific post for a specific user. If it is called, we then reuse our assign_user plug to assign the user into the conn. Also, we’ll need to make sure we don’t try to preload users into a potentially blank array, so we’ll check to make sure the user assigns exists in conn before doing the rest of the work. If it doesn’t, we’ll just return out conn since that will include the invalid user redirection, flash, and halt.

The second index function is a little different. We want to fetch the most recent 5 posts, so we limit it to the most recent 5 posts and preload the users into each post. We don’t need to worry about comments since we don’t display the comments in the Post index. The post index also needs to change a bit using our new current_user modifications and to make the design a little better. Open up web/templates/post/index.html.eex:

Everything beyond this point is just cleaning up the styles here and there. We covered the more significant changes, so I’ll leave it up to the reader to make whatever further modifications they want to clean up the design. Just in case, the code for this will be at https://github.com/Diamond/pxblog so you can check out the other modifications that were made if you want to bring everything in line with my own changes and design.

Fixing Our Tests

We changed some of the layout and functionality, so we’ll have a few broken tests here and there. First, open up our page controller test (test/controllers/page_controller_test.exs) and modify the only assertion to look for “Phoenix Tech Blog”.

Conclusion

When everything is all done, we should see the following for our new splash page (I’m logged in as the admin in the example below):

Our final layout!

And this is what we should see when we grab the Posts index as a non-logged in user (depending on what test data you have loaded):

Our non-splash layout!

This is now a far, far more professional-looking tech blog, and we’re using Zurb Foundation 6 with SASS, built-in jquery, and lots of other nice little bonuses.

Check out my new book!

Hey everyone! If you liked what you read here and want to learn more with me, check out my new book on Elixir and Phoenix web development:

I’m really excited to finally be bringing this project to the world! It’s written in the same style as my other tutorials where we will be building the scaffold of a full project from start to finish, even covering some of the trickier topics like file uploads, Twitter/Google OAuth logins, and APIs!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store