All posts filed under The Site. You can view a list of all the categories here.

August Updates

In which I describe what I've been up to over the last month and a half.

Over the last month and a half I've:

  • Worked on client projects
  • Turned 18
  • Made 13 separate designs for this website, only one of which I liked (you're looking at it)
  • Started work on a new blog system, realized it wasn't worth it and ported all the new code to this system
  • Switched from NewsFire to Shaun Inman's Fever because it has an iPhone interface and because Shaun Inman made it (go Mint)!
  • Bookmarked a bunch of iPhone developer tutorials, which I plan to read and do soon

I put all that into list format because I didn't feel like writing paragraphs about it, enjoy!

Updates to the Website

As the perceptive individual would have noticed, I've re-designed/aligned my entire site. Even the administration panel received a make-over. There's no rhyme or reason behind it. I was just bored. No major features were added to the front-end of the site, everything worked fine so I saw no reason to change. The only difference is how the static pages (About page) are handled. They now use a carbon copy of Thoughtbot's high_voltage baked directly in to the rest of the site (I didn't feel like using the engine, personal preference). There's also a fair bit of optimization going around, mostly through the use of counter cache columns and :include => ...'s in find()'s. On my computer at least, the site seems to run a lot faster.

Administration Panel Make-over

The layout and design remain unchanged for the most part. Everything is now a little more grid-like, and the code has evolved to a little more HTML5-like. New form submit buttons make managing posts smoother:

<%= form.submit "Save" %>
<%= form.submit "Save and continue editing", :name => "continue_editing" %>
<%= form.submit "Save and add another", :name => "add_another" %>

A private method in the posts controller to make these work properly:

def redirect_after_success
  if params[:commit]
    redirect_to(admin_posts_path)
  elsif params[:continue_editing]
    redirect_to(edit_admin_post_path(@post))
  elsif params[:add_another]
    redirect_to(new_admin_post_path)
  else
    redirect_to(admin_post_path)
  end
end

And everything is dandy! If you're wondering what the difference is between private and protected methods, or are confused in any way, check out the Venerable Jamis Buck's post about Method Visibility in Ruby.

Last, but not least, was a new authentication system. Again I went with Thoughbot's code to solve my problems, with their Rails authentication engine, Clearance. Also, as with high_voltage, I put the code directly into my app instead of using the actual engine, which allowed me to customize it to my liking.

Filed in The Site.

A Few Updates

Just pushed some updates to my website. Here's a general list:

  • Re-factored design
  • Posting system updated
  • Comment system improvements
  • Spam filtering on comments (not that I get much spam)
  • Deploying now done with Capistrano
  • Web server changed to Apache with mod_rails

The design took about three days on and off to complete. Majority of the work was ripping out code rather then adding. The forms took the most beating, the current forms were scrapped, in favor of a new one (actually back to the Rails default), and more simple CSS. Adding a spam filter to the comments was the next largest project. In total it took two days, but it was more involved than deleting some HTML and adding more CSS. The administration section is simply built into the interface. There is no /admin page. If one is logged in, they see the edit/destroy links, otherwise they don't. There used to be published and unpublished posts. That function didn't see much action, so I decided to take it out as well.

Before this release I was using SFTP to deploy. Now I've switched to using Capistrano. Also, in place of Nginx and Mongrel, the website now runs on Apache and mod_rails. There is no monitoring software installed yet (I plan to soon), but from my own browsing the speeds have increased quite a bit.

Filed in The Site.

Works in Progress

It's definitely been a good last few weeks for me. First signed on a project for a garden center, and made some good business connections (both local!), secondly I've almost completed my tumblelog application, which as of yet has no name. The only features missing are a few post types, videos, audio and pictures to be precise. Sure they may be the trickiest to implement, but I love challenges. It should hopefully be done by the next VicRuby meet-up (February 25th, 7:30 PM at the Fernwood Inn), so I can show it off.

Here's a few snippets I've found useful as of late:

#
# I use this to convert pixel font-sizes to ems.
#
def em(pixels)
  pixels.to_f / 16.0
end

#
# Gets those nested em line-heights/margins/font-sizes.
# If you know the documents base line-height then it's faster
# to just divide it by the parent's font-size manually.
#
def nested_em(child, parent)
  child.to_f / parent.to_f
end

This is my version of Apple's Time Machine, couple it with a cronjob and you're golden.

#!/bin/bash

rsync -avl --delete --stats --progress "/Users/mat/Documents/Important Data" "/Volumes/External HD/Backups/"
rsync -avl --delete --stats --progress "/Users/mat/Documents/Legal" "/Volumes/External HD/Backups/"
rsync -avl --delete --stats --progress "/Users/mat/Documents/Portfolio" "/Volumes/External HD/Backups/"
rsync -avl --delete --stats --progress "/Users/mat/Documents/Programming" "/Volumes/External HD/Backups/"
rsync -avl --delete --stats --progress "/Users/mat/Documents/Projects" "/Volumes/External HD/Backups/"
rsync -avl --delete --stats --progress "/Users/mat/Documents/School" "/Volumes/External HD/Backups/"
rsync -avl --delete --stats --progress "/Users/mat/Documents/Server" "/Volumes/External HD/Backups/"
rsync -avl --delete --stats --progress "/Users/mat/Documents/Writings" "/Volumes/External HD/Backups/"

That's it for now. There may be a new design in store for my website, but it won't happen till after the release of Rails 2.3.

Filed in Tutorials and The Site.

Search is Back

My Saturday morning work quota is complete, and so is the search feature! (What I won't mention is that I had already written the code last week and just never bothered committing it until now.) Anyway, have fun finding stuff!

Update: Post categories are now viewable; however, the show pages need some prettying up. Also, just to tempt people, the comments count shows up under each post... you just can't write comments yet! (Bad joke, I know)

Filed in The Site.

Previous Version Source

I've never actually "open sourced" anything before, shared it around with friends sure, but never put it online for the masses. To change that, I'm going to release the previous version of my site on GitHub. The only reason(s) that I haven't done it already are that I need to remove/protect certain files (deploy recipes, git repo locations, etc.) so no bad people find out my secrets! It will be out by the holidays, my gift to everyone. For now, enjoy the new website.

Filed in The Site.

A Weekly Affair

Other then the new design and the source code of the previous version being released on GitHub soon. I admit it's pretty quiet around here. So to redeem my self, I plan to learn one new thing about Ruby or Rails each and every week, then write about it here. It forces me to learn, and hopefully, even if it's one in a hundred, someone else will benefit from the article.

Filed in The Site.

About Halfway Through May

I'm not sure what really happened, but the last time I wrote here was back in February. Back then I just started work on a website for a local garden center, Scent-Sational Plants, which has been launched, though it's not fully operational; archiving and photographing every single plant one owns takes some time, so that part of the site is inaccessible for now. The other project I had going at the time was a tumblelog. Everything worked fine, or would have with a little more time, but I just decided to put it on hold. One reason for doing so was the lack of a proper design, and also the pending release of Rails 2.3.

In the meantime I've kept my self... occupied. Everything seems to get more intense as the end of term nears, and being my graduation year makes it even more tiresome (but awesome!). It's only recently that I've found some time to play around in Rails again, and update my website at the same time. The new design is barely worth mentioning, even though it was the first piece I finished. The star of the show is the fresh application running everything. Doing a full re-write was never my original plan; however, it was well worth it. I went all out this time, that means a full admin panel complete with a custom design and lots of nifty widgets.

What's Missing

It may seem a little sparse right now, that's because some pieces haven't yet made it to the public side of the website. Those include categorized posts, multiple authors and a curious comment system. All of which are fully functional, and will slowly be added in due time. The only thing that makes the comments, "curious", is that it's now polymorphic. Which will allow me, one day, to extend it's scope into other parts of the site, say a photo gallery or back-end multi-author editing with criticism comments thing.

What's New

Here are a few screenshots of the admin panel. It's pretty modular, so the basic design from these pages carries into everything else.

The Dashboard

A list of recent activity around the site. It's just done by a global observer on all saves, updates and deletes.

Dashboard Screen

Post List

Lists all posts and basic information about them. The same design is used for categories and users, just different columns.

Post List

Publish Page

A post has a summary, body and extended field, which make up the content of the post. I can select multiple categories, or set the publish date in the future, or even set a custom permalink (I've kept the id-post-title format so as not to break too many links, Update: Changed to just permalink).

New Post Screen

That's all there is to it for now. Eventually I'll add some more features, such as automatic comment expiration, or post drafts/revisions. For now, it does just what I need.

Filed in The Site.

So it's Been a While

That doesn't mean I've forgot about this place, I've just been busy.

The Victoria Ruby Users group is meeting this Wednesday, January 21st. It would be nice to see more people their. Having only two, as we did last time, leads to some good discussions about... Java, and startups. But a few more wouldn't hurt. After all, there are some pretty neat things happening with Rails, such as the Merb merger, and upcoming RailsConf2009 in Las Vegas, or ticket #1202. Ruby 1.9 is also shaping up, a good post by David A. Black explains some key changes.

Filed in The Site.

Hello Comments

Search, categories, and what else? Oh yeah, comments! You can now leave your opinion, negative or otherwise, on any of my posts (that aren't over a week old). So feel free to flame, though you might get banned, but hey! The only bit missing out of the comment system is a way to preview your comment, I'll probably tackle this with a bit of AJAX trickery sometime this week or next. The previous CMS I wrote has all the code for previewing comments; however, the code is a bit dirty, and I'd like to take the time to write a fresh version (and maybe a tutorial to go along with it).

Filed in The Site.

Navigation

Where I reveal the previously hidden navigation.

Prior to this post (give or take an hour), the "navigation" for the site was only accessible indirectly from the footer. I don't think many people even found it, which was fine with me because it wasn't that important. After a couple hours of play time, there's now a "real" navigation bar, at the top if you didn't notice; and a contact page, where you can send me a message.

That is all.

Filed in The Site.

Observer Fun

Where I share the code I just added to this site for email notifications on new comments and messages.

Ever wanted to know how to be notified by email when someone posted a comment on your home-brew blog system?

Prerequisites

You'll need: a working mail server already set up with your Rails application. Check out Step 1: The Setup in, (A Better) Contact Form in Rails.

Step 1: Generate the Mailer and Observer

./script/generate mailer Notifications new_comment

This will create app/models/notifications.rb with a single method: #new_comment.

./script/generate observer Event

This creates app/models/event_observer.rb.

Step 2: Educate Rails

Open config/environment.rb. Anywhere inside the Rails::Initializer.run block, add:

config.active_record.observers = :event_observer

Now Rails knows about the new observer we just created.

Step 3: The Only Real Programming Involved

Open app/models/event_observer.rb, right now it's just a blank class. Let's add some magic beans to it.

class EventObserver < ActiveRecord::Observer
  observe :comment

  def after_create(model)
    Notifications.deliver_new_comment(model)
  end
end

Okay, so we make it observe the Comment model with the #observe method, and add a method to be called after #create is called, which in turns calls #deliver_new_comment method in our mailer (a dynamic method that instantiates the Notifications class, calls #new_comment and delivers the email). That's a lot of calling.

In app/models/notifications.rb, you should have a single method called new_comment.

class Notifications < ActionMailer::Base
  def new_comment(sent_at = Time.now)
    subject    '[domain.ca] New Comment'
    recipients 'you@yourdomain.ca'
    from       'noreply@domain.ca'
    sent_on    sent_at
  end
end

Basically just fill in the method to your fancy. Refer to the Complete List of Action Mailer User-Settable Attributes on Rails Guides for information on what attributes you can set.

It's possible to use the record's data for the email, but without knowing the column information of your Comment model, it's difficult.

Open up app/views/notifications/new_comment.erb. It could look like...

A new comment has been created on your awesome website! Check it out now at <%= link_to "your website", root_url %>!

And yeah...

So, if everything is working correctly, every time someone creates a comment, you should receive an email notifying you.

Make it More Complex

So you want to include more information in that email, and you also want to observe your Message model to see when someone flames you? That's easy.

Assuming your database is structured as follows:

comments:
  author: string
  author_email: string
  content: text

messages:
  name: string
  email: string
  subject: string
  message: text

In app/models/event_observer.rb:

class EventObserver < ActiveRecord::Observer
  observe :comment, :message

  def after_create(model)
    case model
      when Comment then Notifications.deliver_new_comment(model)
      when Message then Notifications.deliver_new_message(model)
    end
  end
end

In app/models/notifications.rb:

class Notifications < ActionMailer::Base
  def new_comment(comment, sent_at = Time.now)
    subject    '[domain.ca] New Comment'
    recipients 'you@yourdomain.ca'
    from       'noreply@domain.ca'
    sent_on    sent_at

    body       :author       => comment[:author],
               :author_email => comment[:author_email],
               :content      => comment[:content]
  end

  def new_message(message, sent_at = Time.now)
    subject    '[domain.ca] New Message'
    recipients 'you@yourdomain.ca'
    from       'noreply@domain.ca'
    sent_on    sent_at

    body       :name    => message[:name],
               :re => message[:subject],
               :email   => message[:email],
               :message => message[:message]
  end
end

In app/views/notifications/new_comment.erb:

<%= @author %> <<%= @author_email %>> wrote a new comment:

---
<%= @content %>
---

In app/views/notifications/new_message.erb:

<%= @name %> <<%= @email %>> wrote a message:

Re: <%= @re %>

---
<%= @message %>
---

Boom! This is, more or less, the same code I use.

Filed in Tutorials and The Site.

New Page, Updated Page

I've finally updated the About page with a little more information about my self. I've also added a Work page, it's just a list of projects that I've had a hand or two in over the last while. Enjoy!

Filed in The Site.

RSS Feed Added

There seemed to be an issue where Google Reader read the escaped HTML of my posts (thanks to David for bringing it to my attention). After some testing, I think I've fixed the issue. I've also added an RSS feed of my latest posts to go along with the Atom feed. Happy reading.

Filed in The Site.

Updated Design

Since Apple just released a bunch of new products, I thought it would be right for me to release my latest product. So here it is, a new design! It doesn't quite deserve the term “product”, I know.

The only product I'm working on is a tumblelog, which I've hinted to in previous posts. Everything is basically complete, it just needs a final polishing before it's good to go. Look for it by the end of this week.

Update: Currently experimenting with my recently listened tracks from Last.fm in the sidebar. It's parsing the feed and displaying it at the moment, but I might experiment with aggregation if it impacts performance too much (which it seems to be doing). Update Two: It was too slow, working on an aggregator.

Filed in The Site and Programming.

Thinking About Sphinx

I just finished installing Sphinx on my slice, and setting up Thinking Sphinx on my website. Previously I was just using a simple search method in my Post model, but it was always a little on the slow side, especially now since I've started to publish more posts. Getting Sphinx running on my development machine was simple thanks to this article. Installing it on my web server was also easy (./configure; make; make install).

The only down-side was the need to manually index and start the Sphinx server. Hello crontab, rake and capistrano.

Capistrano is mainly just for utility, so I can quickly start/stop/index from my local machine.

I put these tasks under the deploy namespace:

desc "Index Sphinx"
task :sphinx_index do
  run "/opt/ruby-enterprise-1.8.7-20090928/bin/rake -f /var/www/matharvard.ca/current/Rakefile thinking_sphinx:index RAILS_ENV=production"
end

desc "Start Sphinx"
task :sphinx_start do
  run "/opt/ruby-enterprise-1.8.7-20090928/bin/rake -f /var/www/matharvard.ca/current/Rakefile thinking_sphinx:start RAILS_ENV=production"
end

desc "Stop Sphinx"
task :sphinx_stop do
  run "/opt/ruby-enterprise-1.8.7-20090928/bin/rake -f /var/www/matharvard.ca/current/Rakefile thinking_sphinx:stop RAILS_ENV=production"
end

Here's the line in my crontab file.

* 0 * * * /opt/ruby-enterprise-1.8.7-20090928/bin/rake -f /var/www/matharvard.ca/current/Rakefile thinking_sphinx:index 
RAILS_ENV=production

This runs the rake command every day at midnight. As you can see, I'm using Ruby Enterprise Edition, though it probably won't make a difference if I used regular Ruby for this.

I also had to switch from SQLite3 to MySQL, in order to use Sphinx, which was easily accomplished by YamlDb!

Filed in Programming and The Site.

Preview Your Comments

You're now able to preview your comments! I spent a little while today fiddling with JavaScript and Rails to get it working nicely. It's really easy to use, just type your comment, hit the preview button, it will apply all my formatting rules to it, the form will be hidden, and a preview pane will appear with your fancy comment in it. The preview pane allows you to save your comment, or to edit it some more.

Filed in The Site.

Experimental Caching

I've added some caching around the site to speed things up a bit. The biggest hang time right now is when Passenger starts up (as my site doesn't receive a whole lot of traffic, it goes sleepy mode often). Hopefully it makes a difference, but we'll see!

Filed in The Site.

Ruby on Rails 2.3.5 Released

Just a quick note, Ruby on Rails 2.3.5 was released last night. I updated the site last night, which brought up some issues with the RailsXss plugin and Erubis, but everything should be working now. Anyway, go update now!

Filed in Web and The Site.

Converted to jQuery

The average reader (if there is such a thing) won't notice anything different. The few (if any) perceptive individuals will notice I've converted to jQuery. I don't have a huge well thought-out list of reasons why, the ones I can think of right now are simply because it's nicer. I mean, GitHub uses it, and they are logically awesome!

There isn't much to this blog, so making the switch was quite simple. The only bits that required actual work would have been the comment preview feature. Various other small bits were converted around the administration panel, but otherwise nothing required an overly large amount of time and dedication to get running. That is all.

Filed in The Site and Programming.

Permalinks on Rails

Rails provides easy ways to change a resource's URI by overriding the to_param method in a model. By default, it's the model's id column.

def to_param
  "#{self.name.parameterize}"
end

This snippet of code will change the models URI to the name column (the parameterize method converts it to lower case and adds dashes where spaces and punctuation were). By storing this in the database, it's as easy as Person.find_by_permalink(params[:id]).

class Person < ActiveRecord::Base
  before_save :generate_permalink
  
  # ...
  
  private
  
  def generate_permalink
    self.permalink = self.name.parameterize
  end
end

This also updates pre-generated routes, so person_path(@person) would correlate to /people/mat-harvard, same with edit_person_path(@person) » /people/mat-harvard/edit. It's a simple way of achieving pretty URLs. The only thing that possibly needs watching out for is duplicates, but that's not what I'm writing about.

So getting Rails to use a different column as a model's id is simple. What if we want something totally different? For example, many blogging engines have dates in their permalinks, like /2009/08/01/posting-for-fun. A popular blog engine, Mephisto can have permalinks like these, as well as (now inactive) SimpleLog. While you could peruse their code and figure out from there (Mephisto's is actually a little more technical mind), I wanted my own clean solution.

The first step was setting up the routing file to pick-up on these types of permalinks. Luckily, the Rails documentation has a great example of just how to do that.

map.connect 'articles/:year/:month/:day',
              :controller => 'articles',
              :action     => 'find_by_date',
              :year       => /\d{4}/,
              :month      => /\d{1,2}/,
              :day        => /\d{1,2}/

That leaves us with these params = { :year => '2005', :month => '11', :day => '06' }. Let's assume this route is meant to find all posts on November 11th, 2005. An article written back in 2007 has a clear and simple solution to such a conundrum: The Rails Way: More Idiomatic Ruby. After a bit of tinkering, I came up with a class method.

def find_by_year_and_month_and_day(year, month, day)
  requested_date = Date.new(year.to_i, month.to_i, day.to_i)
  from = requested_date - 1
  to = requested_date + 1
  posts = find(:all, :conditions => ["created_at BETWEEN ? AND ?", from, to])
end

From that you could figure out how to find all records within a specific month or year (look at the Date class documentation for help).

What I Want

Within the next week or so I'll be rolling out a new permalink system for this blog. It uses much the same technique as outlined above. The big difference is that I wanted permalinks like /2009/dec/18/posting-for-fun. Some of you may recognize this as being Django inspired. In fact I went and browsed the source code of the Django blog, and The B-List, and stole (!) the routes.

map.connect ':year/:month/:day',
  :controller => 'posts',
  :action => 'show',
  :year => /\d{4}/,
  :month => /\w{3}/,
  :day => /\d{2}/

Having the short month name in the URL actually didn't complicate things as much as I thought it would. Date provides an easy method for converting this to the proper number of the month.

def find_by_year_and_month_and_day(year, month, day)
  requested_date = Date.new(year.to_i, Date.parse(month).month.to_i, day.to_i)
  from = requested_date - 1
  to = requested_date + 1
  posts = find(:all, :conditions => ["created_at BETWEEN ? AND ?", from, to])
end

Hopefully that isn't bad programming... (using Date inside a Date to get a Date, and not someone else). The app now knows what do do with a fancy URL, but not how to generate one. Overriding to_param in this case could potentially get very messy, if it would even work in the first place. Going by the excellent examples of Mephisto and SimpleLog, I wrote this instance method inside of my Post model.

def full_permalink
  ['', published_at.year, published_at.strftime("%b").downcase, published_at.strftime("%d"), slug] * '/'
end

Call @post.full_permalink and you get it's full permalink (for example link_to(@post.title, @post.full_permalink)). Clear and simple (at least to me). I extended this and wrote methods for finding posts by a specific month in a year, and a just year (also wrote corresponding routes to match). Nested resources like comments didn't mesh with the routes, so I had to change how they worked slightly. That's all I've got to say right now! I look forward to getting this out on my blog soon.

Filed in Tutorials and The Site.

Sunday Afternoon Deployments

It's a glorious rainy Sunday, a great time to deploy. I talked about writing a new permalink structure for my website a couple days ago. It's now live! After about a week of working on it in my spare time, it's ready to see the light (and rain) of day.

Old Permalinks

The previous permalinks (/posts/1-title) still work. My plans are leave them intact to both be nice to anyone linking to my site with old URL's, and have a "Short URL" type service.

I'll be monitoring the site all of today to make sure no bugs got through, otherwise, enjoy!

Filed in The Site.

Last Year's Statistics

I've managed to keep this website up for over a year now, something that was unimaginable at a time. A nosey person would know that I've been tracking visitors using Mint (I browse source code as well!). Now it's time to reveal some astonishing facts! (Fake enthusiasm.)

This Year

There have been 9,100+ visits, 4,600+ of those being unique.

The top three visited pages are:

Most popular search term: “rails contact form”.

Most popular local search term (using my search function): “subversion”.

Most popular outbound link: Rails API on ActionMailer::Base.

Visits by browser: Firefox (44%), Safari (24%), Chrome (22%), IE (9%).

Visits by platform: Macintosh (51%), Windows (31%), Linux (11%). Did I mention I bought a PC, running Windows?

Random

My most popular referrer is linking to the wrong page because of how many times I've changed permalinks. My second most popular referrer is a page discussing my contact form articles. January 2010 was the all-time most popular month for this website.

Statistics are fun!

Filed in The Site.