Making a Real World Phoenix Blog

Rebuilding a portfolio with Elixir coming from Rails.

Making a Real World Phoenix Blog
Jun 22, 2018 • 33 Min Read • 3278 Words

There’s a lot of articles about how to make a blog in Phoenix/Elixir but most of them are light on features.

Instead of doing the “Hello World” of Phoenix blog apps, I’d thought I’d talk about the real work it takes to make a professional blog with real features you might need.

Jekyll And Static Sites

My last site was made in 2014 in Jekyll and hey, static sites so easy right? I’ll just update from git!

Ha! well that never really happened. After making the site, I never once updated it. A Web UI is way easier to use to update content vs static site.

kidbombay.github.io

I mean I drank the Jekyll Kool aid. It’s a fantastic tool for content that you don’t need to update from anywhere. But this is 2018 and I need to update my site more than once a year. I’m lazy as hell, so static sites are out the picture.

First starts

Having worked with Phoenix before on a small url shortener project for Up All Night, I was a little familiar. That URL shortener was easy to write, crazy fast and I haven’t had to touch the code once in over a year. It just works.

Phoenix 1.3 / Stop changing things

But since then, Phoenix is now running at 1.3 and for some reason they added contexts. Now don’t get me wrong, Chris and team have done an amazing job with Phoenix but what made Phoenix so easy is that as a Rails dev, it was the same concepts/workflow.

Contexts are just another abstraction that frankly I think 99% of projects won’t need. For larger projects where you have multiple developers, contexts makes sense. But for a portfolio site, it’s overkill.

And given the recent upgrade to 1.3, many tutorials on the web are out of date and I haven’t updated my programming Phoenix book (get it, it’s good). So trying to track down issues is hard, cause I can’t code by stack overflow.

But I said no way, I want that Phoenix speed and my site really needed a new look. Not that I had time, but I made time because I was tired of how slow Rails is for well pretty much everything.

Sketch in Sketch. Design in Browser.

I had actually finished a majority of the site design a year prior but never got around to building it. At this point with design and Bootstrap, I make large brush strokes in Sketch to get basic concepts out, but much of my design work is done in browser.

Phoenix live reload made that a breeze. You make a change and the page automatically refreshes. The command R key alone will thank you on those crappy new MacBooks.

Models. No Schemas. No Models?

So what’s in a portfolio? Well for a real project you need a few things.

  • Authentication
  • Authorization
  • Articles
  • Projects

Authentication covers your user schema. Authorization handles who gets to edit what. Articles for your blog posts and Projects for your portfolio. Pretty simple.

Authentication

Authorization, well in Rails world, it’s all about Devise. You put a gem in, do the read me, and bam you are done.

In Phoenix, the world is still new, there’s no clear winners for lots of packages. so I rolled my own, following the great YouTube tutorial here. This dude is great. Super easy to follow along and clear guidance. I didn’t need reset password or anything fancy. Rolling your own with Rails rarely makes sense. Devise is just too good and easy.

But with Phoenix, I got it working pretty easily. That’s the pattern you’ll see very often in Phoenix. You build your own so often compared to using a gem. For lazy Rails devs like me who have bills to pay, time is everything.

But I can’t get stuck in old bad habits.

Now with Phoenix you have an additional abstraction with View classes. Every part of the controller/view/model (now schemas) flow needs one. I didn’t really do much with these, so now I a bunch of empty view classes doing nothing. It doesn’t seem that helpful to have this additional abstraction for a smaller app. It’s very similar to when you scaffold with Rails and you get those helper classes you never touch.

Authorization

After building auth, I needed authorization. Authentication being login/logout and authorization being access control. In Rails, I would reach for Pundit which is a beautiful thing and so easy to work with.

I couldn’t find something like that for Phoenix (again dev by gem/stackoverflow) so I ended up keeping it simple. I just added a admin boolean field to my model that I only change in iEX (no controller/view access) so it’s relatively easy.

Here’s the part I often got stuck with Phoenix and Elixir syntax. Ruby is such a beautiful language. It’s so simple it reads like English. You don’t have ugly symbols and operators ruining your code.

But Elixir has some of those and while I get need for them (I think), it makes learning the language kind of annoying. You get errors all the time and frankly the errors aren’t that helpful. It’s super hard to understand and I just haven’t learned enough to immediately know where my syntax is wrong. I also keep forgetting to add the do to my function definitions. Why is this needed? Are functions blocks? Ugh. Anyway it’s old habits die hard.

def function_name(params) do # why do we need this??
   …
end

Ecto vs ActiveRecord

Working with Phoenix, means learning Ecto which is the replacement for ActiveRecord. Now ActiveRecord is a beautiful thing for it’s easy of scoping, validation and such but it definitely wears pants too big and tries to do too many things.

Ecto is much simpler. I really love that instead of using a model class, you just use a schema. The only thing your model class is responsible for is change set and field definition. Migrations as well are identical to Rails. There’s some issues in documentation with optional/required fields. Some docs say to use it, some don’t. I ended up not using it.

But overall Ecto/Changesets are super easy to understand. You will love the pipe operator, it’s kinda of fun to chain methods by

|> downcase
|> strip
|> etc

Vs in Ruby

my_scope.my_other_scope.my_other_method

I’m a big fan of readability in code.

You aren’t writing code for you, you are writing code for you 6 months from now when you have forgotten everything.

Pipes make code very readable and understandable. While I still have much to learn/understand about functional programming, I dig the super clear transformation vs mutation mindset.

Though for shorter methods

"Capitals".downcase

is way easier to understand vs

String.downcase("Capitals")

The less you have to write, the easier it can be to understand.

Make your life easier

I added some nice features only accessible to admins for managing the site. Like I hide the login link if you have never logged in. But once you do, I show it so it’s easy for me to log back in as admin. A portfolio site is different than most because you don’t need others logging in. You have to make it work for you in a way that will UPDATE YOUR BLOG because other wise, let’s face it, you rather drink a beer.

Pretty URLS

Once authorization was out of the way, I did some basic scaffolding around Articles. For blogs, readable urls are very important and in Rails world, I would reach for Friendly id. There’s nothing like that in the elixir world (full service pretty urls) but I found a package that connects to ecto nicely for creating slugs from strings and Phoenix as very similar to Rails to param method (that I had to google) so friendly_id wasn’t needed.

Great now I got nice friendly ids, basic content, slug, title fields, what next?

The Project Model

Well for a portfolio you need some sort of project model. For mean that means

Title :string
Slug: string, unique
Subtitle:string
Thumbnail, (file field)
Skills: array (string
Content: text

Ok except for thumbnail all pretty easy. Scaffold another controller (and use phx.gen not phoenix.gen cause it changed in 1.3???) and do your html/css changes.

Active Navigation

At this point I had a lot of the basics done. Easy to add articles/projects. Static content for my home/about/contact pages. I started building partials (sorry templates) for navigation and footer and I ran into a gotcha.

For most sites your nav needs to state what page you are on. An “active” link if you will.

In Rails I use the nav_link gem which has great options for figuring when you are actually on the page you need to be active.

For index pages like /articles, /work that’s a no brainer. But how do you mark a link when you are on a show page like /articles/my-blog-post?

There was no obvious easily solution, I found this package that did something similar but it did something weird and added the “Active” class to both the wrapper <li> and the link. For bootstrap that’s a no no and actually breaks the layout. After submitting a bug request I went and wrote my own.

I basically poured in the package and ripped the little I needed to work and that was great. I have now have active navigation that looks good and is easy to understand.

Images and Cloudinary

For most of my Rails projects, I use dragonfly. Now I know some people love their Paperclip or whatnot and now in Rails 5.2 you have ActiveUpload but I realized for 99% of my projects, I was using Cloudinary. Cloudinary is the shit. Super fast image uploading/hosting and CDN. So I had to find a way to make it work in elixir. Arc which is the big elixir package for uploads supports AWS and local uploads but not Cloudinary. Since I was on Heroku and I didn’t want to deal with AWS I tried to figure out how to make Phoenix work Cloudinary.

I found this great open source phoenix app (yay open source) and basically rippled out the Cloudinary bits I needed using the cloudex package.

Getting it to work was kind of tricky because when you delete a project, you need to delete the image on Cloudinary etc. I wrote some custom code to handle this, I don’t know if it’s very elixir-y but hey it works. I am definitely open to feedback on how to improve it.

Using cloudinary’s upload JS widget and Ecto I got my project and article model connected. Now I have super fast images and live preview with cropping without having to do much. Great I can focus on writing crazy long articles that I’ll never finish.

Hosting: Heroku or bust?

For most projects I just push to Heroku. They own my wallet. Goddamn it’s so easy to push. While I would love to muck around with DigitalOcean, I just don’t have time to setup a Ubuntu server and neckbeard my way out of config hell. I swear as soon as someone comes up with a way to deploy as easily on Heroku on Digital Ocean I will give them my first born.

Heroku has well known issues around performance and part of my concern with Rails was performance. Now every engineering decision has trade offs but I also wanted to get my site out quickly, not a month from now. I am not dev ops. I don’t want to config things. I want to get clients and get paid. And design pretty little things that make people happy.

So the basics of Heroku/Elixir are pretty well documented, it’s an easy setup with known issues for the most part. I couldn’t get HTTP zip compression working but oh well, I’ll get to that later. Once I had my DNS setup, most of my site was ready to be ported over from the old site.

Now I could have written some Jekyll to blah blah converter but who has got time for that? I just had 2 browser window opens and copy pasted the small amount of content I needed.

Content Management

For doing a real blog you need a couple of features. One is publishing control. You don’t want to just write something and publish it out there naked. So I added a publication boolean to manage that. For admin, I show a draft badge on draft articles/projects while I’m still working on them. It lets me preview content before I release it. I can always open an incognito window if I want to see my site as a guest.

You also need published_at for projects, articles. It’s not the same as inserted/updated_at. It’s the date you want to display for readers to understand when you completed a project or article.

(Also why Phoenix people did you just not use created_at??)

Who Needs Time Zones Where Are Going?

Now get this, Elixir still doesn’t have support for time zones. Holy shit. [Like I’m not kidding)[https://elixirforum.com/t/call-for-proposals-time-zone-support-in-elixir/14743]. There’s a proposal out there now to help address this but man talk about not being production ready. All my client projects usually need time zone support, so I’m so glad I built this site first before trying to convince a client on Phoenix/Elixir.

I might just be ignorant but from what I’ve read, it’s not that great for time zones yet.

Luckily for a portfolio project only days matters, not minutes or seconds. I added a published_at field and got it work with the built in date_select.

I still have some bug around bootstrap display and the date control and I didn’t want to get into using a Javascript date picker just now, cause weekend.

Ok, Contexts are cool now.

Most features at this point are pretty fleshed out. Remember how I mentioned contexts earlier and complained about them?

Well surprise, now they rock!

I created 2 contexts, one for Account for the user model and one Content for projects and articles.

Because the Content context has methods to get article/get_articles, it makes queries centralized . Everyone is familiar with your Rails active model class having a bazillion scopes but with piping in elixir I was able to reuse every single scope.

IE I wrote the scope once and applied it different models. Way cleaner.

  def published(query) do
    from p in query,
    where: p.published == true
  end

  def by_published(query) do
    from p in query,
    order_by: [desc: p.published_at]
  end

  def list_published_articles do
    Article
    |> published
    |> by_published
    |> Repo.all
  end

  def list_featured_articles do
    Article
    |> published
    |> by_published
    |> limit(3)
    |> Repo.all
  end

In Rails I could have written a query class, but Phoenix just sets this up for you with the context, it’s a good default for sure. My project is rather simple so my Content class doesn’t have too many methods, but let’s see what happens in a different project with more models, sorry I mean schemas needed.

Oh let’s talk about asset management.

Brunch Sucks.

Brunch fucking sucks.

Seriously I hate this NPM/Node/Javascript dependency bullshit. It’s needlessly complicated and docs aren’t clear and I have to find some random gist to get my bootstrap setup working. It works great now but man why do I need node to use Elixir?

I get the whole package dependency shit but the Javascript world is not a good example to copy.

What really sucks because you install a bazillion packages in npm to do anything you can’t use search all files any more in sublime. Your results are littered with all the crap js/css you just installed to make your pretty check box.

Yes I’m sure I can figure out a way not to search in node modules but honestly, fuck Brunch. Or Yarn. Or any of that.

Rails asset management was relatively clean. It didn’t add crazy amounts of dependencies. Or if I needed I could just copy/past the js/css libs and vendor them. So much simpler.

I did get my preferred Bootstrap 4 with custom variables working really nicely. It’s much faster compilation than Rails for sure but the setup time was ouch. And it’s all manual, you can’t just install some packages and get it working. You have to hustle with config.js files, and aah fuck you Javascript.

This gist will save you time.

Doc Doc Doc Docs

While I got stuck on where to put what sometimes, the actual code your phoenix app creates gives some pretty good hints. Documentation is the best feature of any framework and for that Rails still rules compared to any others. The ability of someone to learn your framework and be assured the docs are updated for the brand new version that was released yesterday is so key for community engagement.

Now I’m sure Rails in the early days suffered this at 1.0, 2.0 but since Rails 4, you are pretty much guaranteed the docs are awesome.

I’m not trying to pick on the Phoenix team, it’s just that with massive changes like contexts, project structure and Ecto and so many moving parts all the time, it’s hard to get developers on board if things don’t work in the readme, you feel me?

Almost There

Ok so we have authorization, authentication/ image uploading, content management, asset management, shared templates, shared views now all working nice. I spent a few days pouring over minute design changes probably none of you will notice but hell I care. I’m pretty damn proud of the final product and I think it looks great. Which I almost never say about any of my work lol.

Ok the contact page sucks. Don’t go there.

Actually Writing Content!

Well the whole point of this project was to make it possible for me to write content continuously. And this article being my first one. So please send me feedback. I am sure there are bugs/typos, stupid ideas etc etc.

Oh, the biggest thing I forgot to mention?

Phoenix is fucking fast.

Like holy shit pants on fire fast. All my pages basically load instantly. I haven’t done any real stress testing but on the $7/mo Heroku hobby server, I’m getting 20ms response times.

It’s insane how fast Phoenix is compared to Rails.

This is the best part. Being in Rails world, you are always dealing with caching and optimizations and what not, but with Phoenix, at least at this size of project, I don’t need any of that to get world class performance.

I’ve spent so much time trying to optimize Rails, going from let’s say 800 ms to 100 ms but in Phoenix you start at nanosecond speed!

Like good god, it’s beautiful.

Performance is the #1 feature for so many apps.

If your app is slow, people won’t use it. And while yes you need to be at medium/massive scale for Rails to show it’s warts, it’s just nice not to have even think about it for a long time.

If you are a Rails dev and if you are considering learning Phoenix, do it. You will be super happy. All in all, it took a Elixir beginner like me, maybe about 2 weeks start to finish to make site. And that’s working a couple of hours a day when I’m not doing my Rails job at HireClub (yes sign up if you are looking for a job, we are cool.)

Next Up
Dealing with Impostor Syndrome

Dealing with Impostor Syndrome

We all have it. How can we change it?

Jun 21, 2018