A client recently came back to us to build new features into the project we’ve created together. One of the additions they needed was a blog, which I expected to have ready in a morning. A Rails app! A blog! Simple and easy.
Our client needed to publish evergreen, categorized articles. Their application makes use of Clearance, Clearance middleware, and plain-old-ruby-objects for authentication and authorization. We are very happy with its current architecture, test coverage, and code quality.
- a blog system with image uploads, related articles, tags, etc.
- that uses the existing design and layouts
- with clean and readable code
- no more than a day of work adjusting the new code to our architecture (users, permissions, and styles)
We tried three different solutions and finally decided to roll our own. This is what we learned from each option.
Since the blog-in-fifteen-minutes video is around, the Rails ecosystem has seen several open source blog and CMS solutions.
Web app problems are commonly solved in gems with active open source communities taking care of them. I checked various gems so that we could write and maintain the least amount of code possible.
A first realization I had was that there is no obvious choice for adding a blog to a Rails app.
- There are many projects that are now abandoned.
- There are developer-focused gems, with Markdown fields and no WYSIWYG editor,
git push, rake tasks, image attachments through Amazon S3 and copy-pasting URLs, etc. Examples are Octopress and Toto.
- There are whole Content Management Systems that we don’t need, with features
like static pages, cluttered WYSIWYG editors, multilingual support, etc.
Publify, Comfortable Mexican Sofa and RadiantCMS are examples of this.
monologueis not as big, but still bigger than we needed.
lines-engine felt like a good fit, and I took it for a ride. At first, I
plugged in the engine with no modifications. I liked how it generated the code
instead of relying on hidden views and controllers that the gem exposes. That
way it would be simpler to customize.
I wasn’t happy with it having an authentication implementation which requires a
new database table (
lines_users), which is different from its
table. We could use our existing
users table for both roles. It also brings in
a set of new gems into our dependency tree. I’d rather keep our codebases as
slim as possible, but the deal breaker was its dependency on Carrierwave, while
this app already has a successful paperclip installation, either of which is not
trivial to set up and test in different environments. (
this same issue for us).
lines-engine is written following different coding standards and scores higher
in code complexity than the rest of this app. Merging foreign code into our
repository will make it harder to read and reason about, increasing the chance
of introducing bugs and vulnerabilities.
I decided to modify the code available in the gem and generated by it, but it was too entangled with the features we didn’t need, in a way that stripping out its non-necessary features would have taken as much time for us as building exactly the features we wanted.
Unhappy about this progress installing it in our codebase, we tried using
lines-engine as part of a new Rails application, separate from the main app.
To avoid adding new code, dependencies, and redundant database tables into our application, we thought of creating a new suspenders application (our Rails template). Our scripts would automate the creation of the Rails app and its deployment to Heroku. A new canvas would allow us to fully embrace whatever conventions the lines team has embedded into their software, without the need for adjustments or configurations.
The disadvantages we discussed were:
- We’d need to maintain two up-to-date and secure Rails deployments
- We’d need to copy over markup and styles from the original app
- Each app would need to be deployed independently
linesdidn’t at the time work with Rails 5
- Extra Heroku cost (although negligible)
The advantages didn’t outweigh the disadvantages, and we considered going with a hosted solution: the well-known WordPress.
WordPress has been an effective blogging platform for more than a decade, with close to 37 million websites now hosted on WordPress.com, and thousands of one-click install plugins to extend installations.
With hosted WordPress we wouldn’t need to take care of the deployment process, keep the software up to date and secure, or build and test any user interface. At first I thought we wouldn’t be able to easily reuse the markup and styles we have in our main app, but Brenda (designer on the team) had ported designs to WordPress before, so we signed up for an account to test our assumptions.
While setting the website up we found out that hosted WordPress didn’t allow us to freely edit the templates or theme as we need, and hosting a WordPress project to edit the theme defeated the purpose of using WordPress in the first place.
We decided to spike up our own. This was my first impulse as a web developer who loves Rails, and I consciously postponed it because less software is better. So, hello again Rails! Let’s see how useful it is to “scaffold” Article and Attachment models, and how productive it is to hook the new controllers to our authorization logic.
In about an hour I had an Article CRUD interface with paperclip attachments working. I then found the lepture Markdown editor, a good compromise between a simple implementation and real-time feedback for the writer to understand how will the article display in the browser. Our client already knows some HTML, and could quickly ramp up on Markdown using this editor.
Our Controllers and Policy objects allowed us to quickly build up the CRUD code, hooking up authorization logic quickly and securely. Because all code looks similar, it was easy for me to replicate the tests for authentication and authorization.
We added some logic to show a featured blog post and a featured attachment per post. By the end of the day we had a working blogging engine with as simple of an implementation as we could, and useful for our client and his customers.
Colleagues pointed me to two other alternatives I didn’t consider that day:
- Composing blog posts in WordPress, and have an RSS importer in the Rails application
- Using Contentful to build the blog without the need to build the UI
Rails makes it so easy to spike up a good CRUD interface that for us it’s easier to build simpler features into existing applications, or generate a Rails application with sane defaults through our suspenders template, than checking what’s state of the art in RubyGems for a known problem like a blog.
For anything more complex than this simple version of a blog, I’d argue in favor of using an off-the-shelf solution. You might want to read to gem or not to gem, Elle’s blog post on when does it make sense to incorporate new dependencies into your project.