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>