Hi, welcome to Word of Mike, my little corner of the internet. I am a Software/Web Developer working in North Yorkshire. I mainly write about programming but my other passion is politics so beware. (click to hide)

2013-03-10 18:01:40 UTC

About Time, Too


I've finally rewritten Word of Mike in Rails. Took me two evenings of extremely low-intensity programming, with the Ballmer Peak reached and then surpassed on both occasions.

Not a great deal revolutionary about it. Only thing noteworthy is a bit of routes sugar to give me slugged URLs. This is my entire routes file:

Wordofmike::Application.routes.draw do
  resources :categories
  resources :journals, path: :j
  resources :journals, path: :blog
  match 'login' => 'users#login'
  match 'logout' => 'users#logout'
  root to: 'home#index'
  resources :pages, only: [:index, :new, :create]
  resources :pages, path: '', except: [:index, :new, :create]
end

I've defined the journal resource twice with different path options to give me backward compatibility with my old /blog/ routes — I don't like breaking links! The pages routes are particularly interesting as I wanted to be able to access a page like /:id as opposed to /pages/:id. For the :index, :new and :create actions I define an ordinary resource with no options, and then for all the other CRUD actions I set the path to ''.

The order of these route definitions is very important as there's every chance of route conflicts when you start messing with the natural resourceful routes. The pages routes need to be defined last, otherwise requests for /categories/ for example, will be routed to the PagesController where it will attempt to find a Page called 'categories'. The higher up the routes file the higher the precedence, or simply, the first route that matches is the route that gets used.

Using routes like this does introduce some onus on the admin to make sure he doesn't create pages called 'j' or 'categories', etc, otherwise they won't be accessible.

To make these routes work with the 'slug' for Journal entries, rather than the standard resourceful method of using IDs, I had to change my controllers to grab the record with Journal.find_by_slug!(params[:id]) rather than the standard find method. I also like the way that Rails returns route helpers when you pass an object to methods like link_to, and I wanted to utilise this with my slugged routes too. Turns out this is very simple; somewhere internally Rails calls to_param on the object to get it's ID, so I only needed to override that in my model to return the slug instead.

# This is what I could do
<%= link_to @journal.title, journal_path(@journal.slug) %>

# But this is prettier, right?
<%= link_to @journal.title, @journal %>

To make the latter work, I have to change the model like this:

class Journal < ActiveRecord::Base
  belongs_to :user
  belongs_to :category
  self.per_page = 20

  def to_param
    slug
  end
end

Now it all works!

<%= link_to @journal.title, @journal %>
>> <a href="/j/just-another-ruby-idiom">Just Another Ruby Idiom</a>

Lovely!