Entries tagged with “The Site”
- All (10)
- Entries (9)
- Links (1)
- Photos (0)
Improving on Related Entries
A little while back, I posted about how I was determining related entries for my site. That method worked, but once I redid my site and added my 250+ Flickr photos, it started to really slow down when finding related photos, because of the increase in tags and posts. The real issue was that I was doing most of the work in Ruby, when it really should have been done with SQL. So, I decided to rewrite it.
Note: If you haven’t looked at my previous entry on the subject, you might want to take a look at it, just for the general idea of what I’m trying to accomplish. Essentially, I’m trying to find related posts by comparing tags. Here’s my new Post#related code:
def related(limit=5)
return [] if tags.empty?
join_array = tags.collect {|tag| "posts_tags.id = #{tag.id}"}
tags_join = "AND (#{join_array.join(' OR ')})"
self.class.find(:all,
:joins => "INNER JOIN taggings posts_taggings ON posts_taggings.taggable_id = posts.id" +
"INNER JOIN tags posts_tags ON posts_tags.id = posts_taggings.tag_id #{tags_join}",
:conditions => ["posts.id != ?", id], :group => "posts.id",
:order => "COUNT(*) DESC",
:limit => limit)
end
You can see, as I mentioned, that all the work is being done in the SQL now. I first create a list of tags from the current post, which I then feed into the query to search for other posts with similar tags. The SQL instructs the database to search for any posts with any of these tags, and then orders them based on how many tags match between the 2 posts. The SQL ended up being fairly complicated, with a lot of joins, but it’s now a whole lot faster, because I’m not creating a lot of overhead by dealing with the computation in Ruby. If you’re interested, here’s an example related entry query:
SELECT `posts`.* FROM `posts`
INNER JOIN taggings posts_taggings ON posts_taggings.taggable_id = posts.id
INNER JOIN tags posts_tags ON posts_tags.id = posts_taggings.tag_id
AND (posts_tags.id = 695
OR posts_tags.id = 192
OR posts_tags.id = 195)
WHERE (posts.id != 4322) AND ( (`posts`.`type` = 'FlickrPhoto' ) )
GROUP BY posts.id
ORDER BY COUNT(*) DESC
LIMIT 5
Recalibration
As you may or may not have noticed, I recently redesigned my site, only about six months after my last redesign. I did this for a variety of reasons, the biggest of which was how outdated and restrictive my old design was starting to feel. The new design brings more flexibility and represents a slight change in the focus of my site. It’s perhaps one of the more complete designs I’ve ever done, which is surprising, since I had it done in only about 4 days.
A Little More Personal
Having “web design + development” in my header restricted my post topics.
One issue that always plagued me with my previous design was that I felt compelled to stick to one topic: web development. I remember showing Colin Devroe the design for the first time, and he mentioned that I should take out the “web design + development” from my header. At the time, I brushed the comment aside, thinking it was not much of an issue. As time went on, however, it became more constraining, and, now, with the new design, I’m hoping to make this into more of a personal site. Sure, I’m still going to be posting mostly about the web, since that’s one of my primary interests, but I also hope to have more posts about other things as well. I also imported all of my Flickr photos into a brand new section on the site, which I’m really excited about.
Easier to Navigate
My old archives were painful to browse.
With my old site, it was almost infuriating how difficult it was to discover old posts. The main archive page (pictured above) was just about useless, and it was hard to find related posts once you started browsing. With the new design, I’ve significantly cleaned up my notebook section to make it a whole lot easier to browse. I’ve even found myself browsing my old Flickr photos this way, because it’s so enjoyable. My absolute favorite part is the “filter bar” that appears on each archive page (e.g. the 2008 archives), which allows you to quickly filter out what type of post (entries, links, or photos) you want to see, no matter whether you’re browsing by tag or date. I’ve also improved the related entries algorithm, and it now is more accurate and efficient. (I posted my old algorithm a little while back.)
My New Favorite Font: Calibri
The new archive filter really help to drill down what you’re looking for, and it looks great in Calibri.
When I first started mocking up the new design in Photoshop, I used Calibri, one of the new fonts in Microsoft Office, for the text, expecting to change it later. As I kept working, I eventually fell in love with the font and realized I couldn’t have the site set in anything else. However, this posed a problem, as most people do not have Calibri installed, and, because it’s sized slightly smaller than other fonts, having a fallback of Helvetica or Arial didn’t look very good. To combat that, I put together a simple jQuery plugin to detect if Calibri is installed, which allows me to serve two different versions of the site really easily. If you don’t have Calbri, however, I’d really, really recommend getting it, because it truly is a beautiful font. Check out my about page for info on where you might find it.
Separate Admin Area FTW
Back when I was working on rewriting my site, I toyed with the idea of having all of the site administration inline–that is, instead of having a separate admin area, I would be able to edit a post from the same page everyone else views it, with a sort of WYSIWYG interface. After thinking it over, I ended up keeping the two parts separate, and I’m really glad I did. When I went to put the new design into my Rails project, I didn’t have to worry about making sure my administration functions still worked, because I didn’t even touch that code–I coul d go ahead and change the design completely without breaking the core of the site. I also didn’t have to have the extra hassle of designing to accommodate an administration area as well.
Feedback
Of course, I’m constantly tweaking the site. Right now, I’ve got a list of about 15 things I still need to do, and I’m sure that will keep growing. If you have any thoughts on the new design, please let me know either by commenting on this post or by sending me an email. If you’re reading this through a feed reader, please come and check out my site and see what you’re missing!
Finding Related Entries Using Tags with Ruby on Rails
One of the cool features that I built into my new site is the “related” sidebar box on every entry and link. Using a not-so-sophisticated algorithm, my site automatically picks out other entries that seem to be related to the current entry, which hopefully helps readers navigate to my other content. It really wasn’t too difficult to implement, so I figured I’d go through my thought process and the code that makes it happen.
The Not So Fancy Algorithm
It took me a little while to come up with a way to determine if an entry is “related” that was both accurate and relatively efficient–I could have used some complicated tool that parses the content of my entries, but instead I decided use something that’s a little simpler: tags. To understand how it works, pretend I have three entries:
- Entry A - Tagged with: Turkey, Roast Beef, Cheese, Bread
- Entry B - Tagged with: Bread, Baking
- Entry C - Tagged with: Turkey, Cheese, Bread, Lettuce
Let’s say we’re looking for entries related to Entry A. From just looking at B and C, it’s clear that C should be closest, as they A and C both have something to do with sandwiches, whereas B only talks about bread. To rank the entriesprogramatically, I first do a query to find entries with any of the tags from Entry A. Then, once I have that list, I sort the entries by how many of Entry A’s tags are used. So, in the above example, Entry C would have 3 matched tags, and Entry B would have 2. It’s not a perfect system, but so far, it seems to be working pretty well.
The Code
So, here’s the code that’s performing all the magic:
class Post < ActiveRecord::Base
def related(limit=5)
@related ||=
returning self.class.find_tagged_with(tag_list, :conditions => ['posts.id != ?', self.id], :limit => limit) do |posts|
posts.sort_by do |p|
matched_tags = p.tags.find_all {|t| self.tags.include?(t)}
matched_tags.size
end.reverse
end
end
end
The real meat of the method is in the returning block, so let’s take a look at that:
returning self.class.find_tagged_with(tag_list, :conditions => ['posts.id != ?', self.id], :limit => limit) do |posts|
posts.sort_by do |p|
matched_tags = p.tags.find_all {|t| self.tags.include?(t)}
matched_tags.size
end.reverse
end
What’s happening here is I’m first searching for any entries tagged with the current entry’s tags (I’m using acts_as_taggable_on_steroids), then, with the data that’s returned, I use Ruby to sort the entries by the number of “matched” tags, which then gets returned from the method. Conventional wisdom suggests moving the matched tags part into SQL, since MySQL is more efficient than Ruby at handling data. However, I’m using relatively small sets of information, and I haven’t run into any performance issues yet.
Overall, this method’s working pretty well for me, but I’m sure as I accumulate more posts, I’ll need to refine it some. I’d really like to incorporate some sort of popularity ranking, based on number of comments and views, but that’s not something I’m too worried about at the present.
A Fresh Start
I never thought I’d actually get to this point, but, today, I am releasing a complete ground-up reworking of my site. With Ruby on Rails as a starting point, I was able to develop my very own content management system, and it is now powering everything here (with the help of a few plugins). I’m also excited to have a brand new design up, and it’s one I really have grown to enjoy. Read on for more details on the specifics of the new site.
The Design
Ever since I started using Twitter, I always used a stunning picture of the Crab Nebula as my background. When I started redesigning my site, I used the photo as a placeholder, but after a while it stopped being a placeholder and started driving the rest of the design, so I decided to keep it. The colors in the layout were directly influenced by the image: nearly every color comes directly from the Crab Nebula photo.
One thing I attempted with this was to not hold myself to the notion that there has to be a sidebar on every page. If you take a look at my About and Work pages, you can see where I switched things up. Personally, I think this helps to make it feel a little less like a blog, something I was definitely aiming for.
Even though I’m launching the new design today, there’s still quite a bit of refining for me to do. For one, the notebook page is pretty cluttered, so I really need to go through and organize that a lot better. In addition, several people I’ve shown the site to have mentioned that the header is a bit awkward; having the navigation attached and the title detached throws them off. I’m definitely going to need to find a better way to have that set up.
The Development
Developing the site is something I really enjoyed, and it allowed me to try a bunch of things I’ve been thinking of for a while. The site is built using Ruby on Rails, several plugins, and a whole lot of my own code.
One thing I’m proud of on the site is that every single page is cached. This way, things stay speedy, and the load on the server is lessened. Adding caching in Rails is really easy, and if you’re looking to do it yourself, you’ll probably want to check out this Rails Envy tutorial as well some Railscasts episodes.
For the server setup, I originally was planning to use Dreamhost and Phusion Passenger, but after using it for a bit, I felt like I needed a little more freedom, so I ended up buying a VPS from Slicehost. So far, I’ve been thrilled with Slicehost’s service and performance, and I’m definitely considering moving more projects over to them. As far as the technical side of things, I’m still using Passenger to run the site, though I might test out using Mongrel to see if that’s any faster.
Next Steps
I’m really excited about the new site, but I’m not done yet. Like I mentioned before, I still have some design tweaking to do, but I also have a lot I want to implement under the hood. There are bound to be issues that come up, and I’ll be hopefully fixing them as fast as possible, but if you run into something, please let me know.
I would love to hear any feedback (negative or positive) you have about the new site, so please leave a comment below!
Redevelopment Update
I put together a quick video showing where I’m at with the new design and backend for KyleSlattery.com. Take a look, and let me know what you think!
Building a CMS: Simplifying Posts with Single Table Inheritance
“Posts” will make up the majority of my site’s content, and there will be a few different types: articles, reviews, links, and comments. While I could create separate tables in the database for each, I’ve decided to utilize Rails’ single table inheritance, whereby multiple models share the same table and some common behavior. However, STI is not limited to Rails; it’s a general design pattern where one table is used for multiple objects or models.
Rails and Single Table Inheritance
In Rails, every table in the database is represented as a “Model” (which follows the model-view-controller design). So, for instance, a standard Post might look something like this:
class Post < ActiveRecord::Base
# model methods go here
end
This model will store its data in the “posts” table in your database. Now, to implement STI in Rails, all I have to do is create models, but instead of inheriting from ActiveRecord::Base, I inherit from Post, like below:
class ArticlePost < Post
# model methods go here
end
Now all that’s left is to add a “type” column to the “posts” table in the database, and Rails automatically figures out the rest. I’ll go into more detail about this in a future post.
Why STI is Awesome
The basic reason I wanted to go with STI is it makes it very easy to pull different types of data from the database at once and display them. Instead of making a query for each type of post, I can just do @posts = Post.find(:all), and Rails pulls every type of Post and even makes each the right object type (e.g. if the table row has a type of “ArticlePost,” Rails returns an ArticlePost object, not just a Post object).
Single Table Inheritance also makes it very easy to share behaviors between different types of posts, especially the way it’s implemented in Rails. Since each object is a child of the Post model, I only have to write standard behavior once, such as post status and commenting.
Potential Pitfalls
One of the main problems with STI is that it can lead to cumbersome database tables with many columns, since each child model might require different fields. When the database table gets very large, this could potentially cause issues and slowdowns. However, in my case, since each post has the same basic fields (title, body, author, etc.) with only a few specific fields (product name for reviews, link urls for link posts, etc.), I don’t see this becoming an issue. Also, since I’m never expecting the database table to reach, say, 100,000 rows, it’s doubtful there will be much of a performance loss.
Comments as Posts?
While it was a simple decision to handle articles, reviews, and links as subclasses of “Post,” I had a little trouble coming up with how to best handle comments. I had two choices, either I make comments just another type of Post (i.e. CommentPost), or I create a new table and model just for comments. In the end decided on STI, because, once again, I can take advantage of shared behaviors to cut down on code. Also, since a comment is just a “Post,” it will make it easy to “comment on a comment” to create a threaded discussion.
More to come
Since this was more of an overview of STI, in a future post, I’ll try to explore more of Rails’ implementation of single table inheritance and how to best use it.
Building a Content Management System on Rails
In my first post, I mentioned building a content management system from scratch. To introduce the project, I figured I should go through my reasons for it, and what I want to accomplish.
Why write my own?
Sure, there are loads of systems out there for running a web site, and it’d be really easy to take something like the incredible ExpressionEngine and get it to do what I want. However, using existing software means I don’t get the experience of writing one myself.
Also, by writing it myself, I don’t have to try and work around an existing structure to get my site to operate the way I want. If I want a feature, I can just dive into the code and add it, rather than reading through plugin documentation and existing code.
What’s it going to do?
A few of the features I want to implement:
- Blog Posts
- Link Posts (i.e. my own del.icio.us)
- Review Posts
- Portfolio Management (to replace my current portfolio)
- Comments
- Static Page Management
- RSS Feeds for everything
- Caching System
- User Management
This is a pretty general list, but as I start working on it, I’ll go into detail about each of the site’s features.
Why Ruby on Rails?
Simply put, I love Ruby, and I love Rails. If you’ve never used either, however, don’t despair! Although I’ll have a lot of Ruby and Rails specific material, my focus will be more on designing the structure of the application, rather than going through the underlying code.
Stay tuned!
I’m going to try to post pretty regular updates on my progress, so make sure to check back often if you want to see how it’s going!
A New Beginning
I’m no good at introductions, but I feel like my first post needs to accomplish something, so here we go, a brief introduction to me and the site.
All About Me
I’m Kyle Slattery, a college student and freelance web developer and designer. Technology and the internet have always been interests of mine, and I love being able to do something I enjoy for a job. You can see some of the work I’ve done in my portfolio, and I also hope to be able to showcase my work through this blog as well. At some point, I’ll write up a complete bio, and put it in my about section, but for now, this will have to do
The Site
First things first, yes, I realize I am a web designer, yet I’m using an existing WordPress template. I really wanted to get this site up, so I haven’t yet had the time to put together a design. I’m also planning on coding my own content management system for the site (more on this later), and I’ll likely want to redesign the site when I do that anyways.
My plans for this site are pretty simple: I want a place to communicate my thoughts on web development and design and also somewhere to post various helpful tips I’ve found throughout my web adventures. Right now the site is powered by WordPress 2.5, but I’m planning on writing my own content management system with Ruby on Rails. Posts about this process will likely take up a lot of the space on this site, as I think documenting my trials and tribulations could be helpful to other developers out there.
I don’t really have much more to say than that, as my posts will hopefully speak for themselves. Enjoy!
