Entries tagged with “Code Snippets”

Sass Without the Hass(le)

For a recent project, I decided to try out Sass, a “meta-language on top of CSS,” which allows to do all sorts of neat things like use variables, do math, and have mixins. The only problem: since you’re not writing CSS, it has to be compiled whenever you want to view your page, which can be pretty annoying if you’re just working on a static template (which I was).

At first, I was using the standard command: sass input.sass output.css, but that became too tiresome, and I was struck with an idea–what if I just created a server solely for serving the compiled CSS file? Using Sinatra, I was able to make a dead easy way to use Sass while working on a static template. Follow along to see how you can do this yourself.

First, make sure you’ve got the haml and sinatra gems installed:

gem install haml sinatra

Now, in your development directory, create a file called app.rb and paste the following code:

require 'rubygems'
require 'sinatra'
require 'haml'

get '/style.css' do
  headers 'Content-Type' => 'text/css; charset=utf-8'
  sass :style
end

Now, create a views/ directory in that same folder, and drop a style.sass file in there. This is where you’ll be writing your Sass. Now, you need to start up your Sinatra server, and to do that, just run the following command:

ruby app.rb

Now, if you go to http://localhost:4567/style.css, you’ll see your compiled CSS, and every time you update your Sass file, the code is recompiled. Just change the CSS <link> tag in your HTML template to point to the style.css file, and you’re ready to go!

Posted on June 19, 2009 2 Comments
Tagged with: , , , , , ,

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

Posted on April 13, 2009 Leave a Comment
Tagged with: , , , , , , ,

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.

Posted on November 11, 2008 2 Comments
Tagged with: , , , , , ,

Simple PHP Caching Using Output Buffering

I’ve worked on quite a few PHP projects recently, and all of them have required some form of caching. From working with each, I’ve come up with a pretty efficient method for caching code using PHP’s output buffering. It ends up being really quick and super flexible.

Output Buffering Basics

Output buffering is a pretty simple concept: instead of letting PHP return data to your user’s browser, you capture it and store it in a “buffer,” and you can decide what to do with it. Here’s a simple example:

ob_start();
echo "Hello!  This is buffered.";
$buffer = ob_get_clean();

Let’s go through the code line-by-line. The first line calls ob_start() (docs), which starts output buffering. The next line normally would be sent to the browser. Instead, since I called ob_start(), it gets stored in our buffer. The third line takes the current buffer and assigns it to the $buffer variable and stops the current buffer, all using the ob_get_clean() function (docs). It’s really simple stuff, and it becomes very powerful when used correctly.

How Caching Will Work

For this post, I’m going to be caching a simple API, and the general process will work like this:

  1. A user makes an API call, something like http://mysite.com/api/?method=myapp.search&type=people&query=Kyle
  2. If a cache file exists for the call, and it is younger than 15 minutes, skip to #6.
  3. Start buffering PHP’s output.
  4. Run the code to process the request.
  5. Save the contents of the buffer to a file, with a unique filename.
  6. Return result to the user.

Where Cached Output Will Be Saved

To save the output, I’m going to be creating a file for each unique request. For this application, the request will be unique based on the GET parameters passed. To do this, I’ll be creating an MD5 hash of an alphabetical list of GET keys and values. Here’s the function:

function cache_key() {
  $keys = array();
  foreach($_GET as $key => $value) {
    $keys[] = $key . "=" . $value;
  }
  sort($keys);
  return md5(implode('&', $keys));
}

function cache_filename() {
  globals $cache_dir;
  return $cache_dir . '/' . cache_key() . '.cache';
}

Please note that this will have to be customized based on what exactly you’re caching. For instance, if you’re caching individual pages, you may want to create the key using the path to the page. Whatever it is you’re using, just make sure it is unique and consistent for each page.

Checking The Cache

When a request is made, it’s necessary to first check to see if it has already been cached, and, if it has, whether the cache hasn’t expired. I’ll be using the filesystem to achieve this:

$cache_time = 15*60; // 15 minutes in seconds

function cache_exists() {
  globals $cache_time;

  if(@file_exists(cache_filename()) && time() - $cache_time < @filemtime(cache_filename())) {
    return true;
  } else {
    return false;
  }
}

So what exactly is going on here? If you take a close look, we’re using the file_exists() (docs) and filemtime() (docs) functions to see if the cache file already exists and, if it does, whether it’s recent enough to serve (in this case, if it’s less than 15 minutes old, the function returns true). I’m placing @ signs before these two functions so that, if they fail, it doesn’t return an error. Instead, the function will just return false and the code will run as if no cache file exists.

Putting It All Together

Now, it’s time to get everything working together. First, a couple of necessary functions for saving and reading the cache:

function read_cache() {
  return file_get_contents(cache_filename());
}

function save_cache($value) {
  $fp = @fopen(cache_filename(), 'w');
  @fwrite($fp, $value);
  @fclose($fp);
}

Now, a few calls to wrap around your code:

function start_cache() {
  if(cache_exists()) {
    echo read_cache();
    exit();
  } else {
    ob_start();
  }
}

function stop_cache() {
  $data = ob_get_clean();
  save_cache($data);
  echo $data;
}

And to implement it, this is all you need to do:

start_cache();
// Your code that needs to be cached
stop_cache();

And you’re done! All-in-all, it’s a very simple way to achieve a very powerful result.

Drawbacks to This Method

The first thing you want to keep in mind when using this caching method is that it caches the entire page. This can be good: if everyone visiting the page sees the same content anyways, why not cache it for everyone? However, if you’re serving a page that appears different to different users, it can be a bad idea. For instance, what if an administrator visits the page, and it gets cached? When the next non-administrator visits, they’re going to see all the administration information. Bad news.

Also, due to the simplicity of this method, there’s no way to easily expire the cache of a single page. Let’s go back to the blog entry example. If you decide to make a change to the entry, you’ll have to wait at least 15 minutes before the cache is cleared, or you have to go in and delete all the cache files (since it’s difficult to determine which file goes with which page). For many applications, this probably won’t an issue, but it’s something to keep in mind.

Download the Source

Hopefully, this was helpful. If you’d like to download the entire source, you can grab it here.

Posted on September 16, 2008 11 Comments
Tagged with: , , , , , ,

RESTfully Forward Users to FeedBurner in Rails

After launching my new site, I realized I had forgotten to use FeedBurner to track my RSS feed subscribers. Because FeedBurner requires that you forward users to your feed on their servers, I needed a way to forward users along, but I also wanted to make sure that if FeedBurner’s spider came to the same feed URL, they would be served the source RSS instead of being forwarded. My solution ended up like this:

class NotebooksController < ApplicationController
  def show
    respond_to do |format|
      format.html
      format.rss do
        unless request.env['HTTP_USER_AGENT'] =~ /feedburner/i
          redirect_to 'http://feeds.feedburner.com/KyleSlattery'
        end
      end
    end
  end
end

If you take a close look at the, all I’m doing is checking the user agent of the request, and unless it’s FeedBurner, I redirect the user to the “burned” feed. If it is FeedBurner, things go ahead normally, and the RSS feed gets rendered.

This means that instead of creating separate actions, one that forwards to FeedBurner, and one that renders the RSS, I just have one action/URL that does both: http://kyleslattery.com/notebook.rss. So far, it’s worked great, and doing it this way really helped to keep my code clean and RESTful.

Posted on August 26, 2008 3 Comments
Tagged with: , , , ,

Posting to Brightkite using ActiveResource and REST

The other day, I came across Brightkite’s REST API. After taking a look at it, I decided it was the perfect opportunity to try out ActiveResource, the dead simple way to consume RESTful resources. In 20 lines, I was able to put together a simple script to find your most recent check-in on Brightkite and then post to that place.

A Quick Intro To Active Resource

First off, here’s an idea of just how easy it is to connect to a REST API using ActiveResource. Take, for instance, the “places” resource in Brightkite; these URLs all have the base http://brightkite.com/places. To interface with places, all it takes is this:

class Place < ActiveResource::Base
  self.site = 'http://brightkite.com'
end

That’s it. To get all the places, just do Place.find(:all). To create a new place, all it takes is Place.new. Amazing, to say the least. There’s a lot more that’s possible, so I recommend you check out the ActiveResource page on the Rails wiki.

The code

Below are the 20 lines necessary to post a note to Brightkite through the API. Just change USERNAME and PASSWORD to your username and password and change the note text at the bottom, and you’re ready to go. While this is a pretty simple example, it shows just how powerful a well constructed REST API can be.

Posted on August 11, 2008 21 Comments
Tagged with: , , , , ,

Pass Blocks to Your Markdown Helper

For the new site, I’m going to be using Markdown to handle the formatting of all of my content. I created a simple helper to make things easy:

def markdown(str)
  RDiscount.new(str).to_html
end

(Note: I’m using the RDiscount library instead of BlueCloth, for reasons discussed here)

However, what if I wanted to add a “Read more” link at the end of the entry excerpt? I’d have to do something like this:

<%= markdown entry.excerpt + link_to("Read more", entry_path(entry)) %>

This way didn’t really appeal to me. What I really wanted to do was just pass a Ruby block, like this:

<% markdown do %>
  <%= entry.excerpt %> <%= link_to "Read more", entry_path(entry) %>
<% end %>

In order to do this, I just had to modify my markdown helper a bit:

def markdown(str='', &block)
  str    = capture(&block) if block_given?
  result = RDiscount.new(str).to_html

  block_given? ? concat(result, block.binding) : result
end

And, just like that, I can now pass blocks to my Markdown helper.

Posted on July 15, 2008 Leave a Comment
Tagged with: , ,

PHP Facebook Paginator

While building the Viddler Facebook application, I needed to create a pagination tool that worked just like Facebook’s. After looking at their HTML and their logic of what pages to display, I came up with one, which I’m releasing for anyone to use. The function takes 5 arguments, in the following order:

  • $base_path: The base path for pagination. For instance, if /videos/4/ was page 4, $base_path would be “/videos”
  • $cur_page: The current page number
  • $total_items: The total number of items on the page
  • $per_page: The number of items that are displayed on each page
  • $footer_bar: If set to “true” this does not include the “Displaying items 1-5 of 10” text, and styles it as a footer paginator, instead of a header paginator.
  • $name: What you’re paginating. This shows up as “Displaying $items 5-10 of 40”

Here’s an example:

<?php echo paginator('/videos', 2, 44, 5, false, 'items'); ?>

And here’s what it would look like:

Paginator example

You can download the source here. Hopefully this helps someone!

Posted on July 8, 2008 7 Comments
Tagged with: , , , ,

Organize Nested Resource Controllers More Efficiently in Rails

Nested resources are awesome. If you want to have a blog with entries that have comments, the resources are dead simple:

map.resources :entries do |entry|
  entry.resources :comments
end

Awesome, now you have set up paths like entries/3/ and entries/3/comments/ using an EntriesController and a CommentsController. What if, however, you want to have a base comments resource (/comments/) to show all comments? You already have a CommentsController, and it doesn’t do what you want. To solve this, I do something like this:

map.resources :entries do |entry|
  entry.resources :comments, :controller => 'entries/comments'
end

map.resources :comments

Now, you have all your routes set up, and you can have separate controllers, Entries::CommentsController (which lives in controllers/entries/comments_controller.rb) and CommentsController. Just remember when generating the nested controller to use the proper name, like so:

ruby script/generate controller entries/comments

Posted on June 24, 2008 Leave a Comment
Tagged with: , , ,

Releasing Java Vector Class

This semester, I took a class called “Computational Physics,” where we simulated various physical properties. For my final project, I wrote a simulation of the Solar System, and in the process, I wrote a “Vector” class for Java. It allows you to do 3 dimensional vector math operations pretty easily, like in the examples below:

// Create vector <1,2,3>
Vector v1 = new Vector(1,2,3);

// Unit Vector <0.27, 0.53, 0.80>
Vector unit = v1.getUnitVector();

// Magnitude (3.74)
double mag = v1.getMagnitude();

// Get each value
double x = v1.getX(); // 1
double y = v1.getY(); // 2
double z = v1.getZ(); // 3

// Multiply v1 by scalar (<5,10,15>)
Vector scalarM = v1.scalarMult(5);

// Create vector <-4,-5,-6>
Vector v2 = new Vector(-4,-5,6);

// Add v1 and v2 (<-3,-3,-3>)
Vector add = v1.add(v2);

// Subtract v2 from v1 (<5, 7, 9>)
Vector sub = v1.minus(v2);

// Dot v1 and v2 (-32)
Double dot = v1.dot(v2);

// Cross v1 and v2 (<3,-6,3>)
Vector cross = v1.cross(v2);

I’ve never really used Java before, so my code might not be the best, but it gets the job done. If you want to download the Vector class, here’s the link. If this comes in handy to anyone, I’d really appreciate it if you left a comment!

Posted on May 4, 2008 Leave a Comment
Tagged with: , ,

Cleaning Up User Submitted Data

A little while back, I complained about WordPress’ handling of URLs without “http://”. While it turns out WP actually handles these correctly, it brings up the question on how to handle a user’s inputted data. It’s always important to format or sanitize incoming data, and for items like URLs, which have a well-defined format, it’s really easy to do. Here’s how to do it in Rails.

One of the great things about Ruby is the way it treats just about anything as a method, so if I call link.url = "http://website.com", it’s actually calling the method Link#url= with the parameter of “http://website.com”. So, to intercept incoming data, I just overwrite the default url= method in my Link model:

class Link < ActiveRecord
  def url=(new_url)
    if new_url[0..6] != 'http://'
      new_url = 'http://' + new_url
    end

    super(new_url)
  end
end

So, now, when I set the url, it’s automatically formatted correctly. Some may advocate putting something like this in a before_save callback, but personally, I like to make sure the data is always correct, even when it hasn’t yet been saved.

Posted on April 15, 2008 Leave a Comment
Tagged with: , ,

Clean Up Your Code By Overwriting Methods

Just wanted to share a quick Rails tip that has come in useful for me in the past. Let’s say you’re creating a forum, and when users register, they create a username (like “kyleslat”). However, they can edit their profile and add their full name (like “Kyle Slattery”). They also can decide what they want to have displayed on their posts (like “Kyle S.”). All of these are fields in the database (username, full_name, and display_name, respectively). Now, when writing your templates, you have to make sure you display the correct name. If you use if-statements, this could be really messy:

<%=
    if @user.display_name
      @user.display_name
    elsif @user.full_name
      @user.full_name
    else
      @user.username
    end
%>

Luckily, Ruby has a nice syntax that can compress that into the following:

<%= @user.display_name || @user.full_name || @user.username %>

However, you’ll likely want to display this in many different places on your forum, and what if you want to change the logic? That means a lot of code to change, and it’s really likely you’ll miss somewhere. But, what if you could just call @user.display_name, and it gave back the right name? Thanks to the ability to overwrite methods, this is really simple to do. Just do the following in your User model:

class User < ActiveRecord::Base
  def display_name
    super || full_name || username
  end
end

Now, if you want to change what displays for a user’s name, you only have to change it in one place, rather than throughout your code.

Posted on April 8, 2008 1 Comment
Tagged with: , , ,