Photo-1 Photo-2 Photo-3 Photo-4 Photo-5 Photo-6

@brentmc79

@brentmc79

Full-time web developer. Part-time smart ass.

I'm Brent Collier.

After a year and a half as an engineer on Twitter's Trust & Safety team, I'm looking for my next gig. Contact me if you know of something interesting.

#

Making Subversion less painful with git-svn

Posted on 04/21/2009

Today I began helping out on an Intridea project that (by the client's request) uses Subversion as their revision control system instead of Git.  Initially I was a bit dismayed.  Hell, I actually felt a little sick to my stomach.  Git has treated me very well over the past year, and I hadn't touched a Subversion repo in even longer.

Git-svn had crossed my mind, but it wasn't until a coworker suggested it that I decided to give it a try.

The first thing was to get it installed.  I followed this tutorial and only had to make one small change.  Adding /opt/local/libexex/git-core to my path didn't work.  I did a quick whereis to find out that my git-svn executable is in the /usr/local/git/libexec/git-core/ directory.  I updated my path and everything was kosher.

Now to set up the repo.  Most of the tutorials that I found covered setting up a new svn repo with git-svn like this one, but in my case, the svn repo had been around for quite some time.  Being the wannabe-know-it-all that I am, I decided to just go ahead an clone the svn repo, like so:

git-svn clone http://path-to-the-svn-repo

After about ten minutes of watching the clone chug away, I thought something was up.  Well, it turns out that if you don't include the proper options, the clone will pull down all branches, tags, whatever.  I didn't want, or need all of that.  All I wanted was trunk.  After a brief glance at the git-svn docs, I tried again with the --trunk flag.

git-svn clone --trunk http://path-to-the-svn-repo

Aparently, the -s option also works.  It tells git-svn that you svn is in the standard layout with trunk, branches, tags, and whatnot.

This time it ran for only five minutes before I asked myself wtf was going on.  I realized that it was pulling down every single revision, which I really didn't need.  I would've stopped it and tried again with the --revision (-r) flag which allows you to specify a revision number, or range of revision number, but the clone was already at rev 900 out of 1100, so  I just let it ride.

Once that was done, I was good to go.  I could pretty much just treat it as a regular Git repo until I was ready to push any changes back to the svn repo.  I used this tutorial by Clinton Nixon, who I had recently seen do a talk on Scala at the Developer Day in Durham, to help guide my general git-svn workflow.

#

Archive links, quick and easy

Posted on 04/14/2009

So I finally got around to replacing the dummy text in the sidebar with real, working archive links, and it was stupidly easy.  Check it out...

First, I added a helper method to take all published posts and group them by the month they were created.

def archives
  @archives = Post.published.in_order.all.group_by { |t| t.created_at.beginning_of_month}
end

Then I used that helper method to display links for each month in which posts were created.

<ul>
  <% archives.each do |month, posts| %>
    <li><%= link_to(month.strftime('%B')+" (#{posts.size})", archive_path(:month => month.month, :year => month.year)) %></li>
  <% end %>
</ul>

You probably noticed the archive_path named route that the links point to. Here's how I set it up.

map.archive '/posts/:year/:month', :controller => 'posts', :action => 'archive'

That route points to the archive action of the posts controller which merely retrieves the posts created within the specified month and renders the list view.

def archive
  @posts = Post.published.in_order.from_month(Time.parse "#{params[:month]}/#{params[:year]}").paginate(:page => params[:page], :per_page => 5)
  render :action => 'index'
end

The archive action uses a from_month named scope on the Post model to restrict the find to all posts created within a given month.

named_scope :from_month, lambda { |month| {:conditions => {:created_at => month..(month + 1.month)}} }

That's it. That's all it takes to set up simple archive links for your blog.

#

Polymorphic many-to-many associations in Rails

Posted on 04/12/2009

Setting up polymorphic associations is ridiculously easy in Rails.  Setting up many-to-many associations in Rails is also ridiculously easy in Rails.  However, setting up polymorphic many-to-many associations in Rails is more difficult, but only slightly.

Recently, on an Intridea client project, I had one particular model that had many-to-many associations with several other models in the app.  The thought of multiple join tables in the database didn't sit well with me, so I decided to consolidate things a bit.

Now I can't use the actual models from the app without possibly giving away the yet-to-be-launched app.  So instead, I'll use an example that we're all familiar with, tags and taggings.

You know the drill.  You have your common model, Tag.

class Tag < ActiveRecord::Base
  has_many :taggings, :dependent => :destroy
  has_many :books, :through => :tagings, :source => :taggable, :source_type => "Book"
  has_many :movies, :through => :tagings, :source => :taggable, :source_type => "Movie"
end

Your join model, Tagging.

class Tagging < ActiveRecord::Base
  belongs_to :taggable, :polymorphic => true
  belongs_to :tag
end

And your taggable models, Book and Movie.

class Book < ActiveRecord::Base
  has_many :taggings, :as => :taggable
  has_many :tags, :through => :taggings
end
    
class Movie < ActiveRecord::Base
  has_many :taggings, :as => :taggable
  has_many :tags, :through => :taggings
end

Everything in Tagging, Movie, and Book is pretty much your standard setup.  This gives you all the normal associations.  You've got tag.taggings, book.tags, movie.tags, and tag.taggable.

It gets a little trickier when you want to find all movies (or books) associated with a tag.  There are a number of ways that this can be done.  You could use some crazy joined finder call on Movie, or find all Taggings with a particular taggable type (or a named scope) and collect the movies, or do it like up above.

has_many :movies, :through => :taggings, 
                  :source => :taggable, 
                  :source_type => "Movie"

This association allows us to access a movies with a particular tag directly from the tag object itself.  It's just your typical has_many association, but with a few more options.  The :through option says that movies can be accessed through our join model, tagging.  Rails normally would expect there to be a movies association on tagging, but the :source option tells Rails to examine the taggable association instead.  Similarly, the :source_type option specifies the class (or type) of the polymorphic association that we trying to retrieve.

So remember when you want bidirectional class-specific many-to-many polymorphic associations, :source and :source_type are your friend.

#

a little search engine optimization never hurt anyone

Posted on 04/07/2009

After continually receiving lame page-rankings on my previous blog attempt, I thought this time that I might spend a little more time to get a bit of my content into Google search results.  I've never really messed with SEO before, so this is a bit of a first for me.

Off the bat, I only really knew (thought I knew) of two ways to help increase page rank:

  1. meta keywords
  2. meta descriptions

Turns out I was wrong.  These days, the keywords don't really help all that much, and the description -- that's just used to display a little snippet of your content in the search results.  Despite their near-uselessness, I still implemented them anyway.  ;)

What my Googling did recommend was this:

  1. descriptive page titles
  2. canonical url tags
  3. submitting a site map

So I updated the post view to display the post title in the page title -- nothing too ground-breaking there.  I'm still up in the air about the canonical url tags since I know there's only one possible url to reach any of the content on this site, although I still may implement that later.

For the site map, I took a look at Google's Webmaster Tools which informed me that I could submit an RSS link ass my site map.  This led me to implement an RSS feed, which I hadn't yet done.  Within an hour of submitting the link, Google had index the whopping two posts that I had created.  Now I just need to migrate the content from my previous blog.

So hopefully all of that will be enough to get me a few more page views from people that aren't my friends or coworkers.