Sep 04

I really like the app on AngelSoft’s new homepage.

A long time ago I created an app that would post messages to the homepage in a ticker when site visitors would do stuff. It was for a liberal political action NGO. From the homepage of this NGO’s site the ticker would flash messages like “A member just sent a fax to Senator Jim Webb about Senate Bill 1022″ or “Bill Jones just became a new member. Welcome Bill!”

I like how they’ve taken that concept and put it on a map. Nice.

Funny how we forget cool ideas from long ago. And funny how we forget that there’s always a chance to build off of old ideas to create newer, better ones.

Great work, AngelSoft. I expect to see a lot of people follow suit.

Jul 23

The lastest version of VoteFu has a few useful enhancements:

  1. Protect against mass assignment forgery. The params hash will only be consulted for :vote => true or false. The rest has to be assigned in the controller.
  2. The acts_as_voteable mixin now has support for tallying votes.

The documentation will be updated tonight, but briefly, here is what you can do with the new tally() method:

1
2
3
4
5
6
7
8
@items = Item.tally(
  {  :at_least => 1, 
      :at_most => 10000,  
      :start_at => 2.weeks.ago,
      :end_at => 1.day.ago,
      :limit => 10,
      :order => "items.name desc"
  })

This will select the Items with between 1 and 10,000 votes, the votes having been cast within the last two weeks (not including today), then display the 10 last items in an alphabetical list.

More to come. Enjoy!

Jul 21

Quotes. I love quoting people. I have a ton of quotes saved in text files, on my blog, in my various mood messages on IM platforms, and who-know-where-else.

I decided to build an application to manage, organize, and syndicate quotes. You can read more about it on my project page for MyQuotable.

If you read this blog, you are invited to participate in my open alpha of MyQuotable.com.

Early Alpha image of myquotable.com

Early Alpha image of myquotable.com

Jul 14

UPDATE:

I made the classic coder mistake, and didn’t dig into the plugin code before working around it. I am leaving this post up instead of being embarrassed and deleting it because it a good example of why you should read your plugin code. After reading the code, I found that TAGLIST IS JUST AN ARRAY: you can simply do this and avoid all of the filter magic that I put in place below.

1
2
  # in config/initializers/tag_list.rb
  TagList.delimiter = " "

Drat. That’s way better.

As it turns out, this answer is in the README for acts_as_taggable_on_steroids, but not in acts_as_taggable_on. I’m sending Michael a note to ask him to include that detail in the documentation.

Original Post

Michael Bleigh’s acts_as_taggable_on plugin is a useful extension of acts_as_taggable_on_steroids.

When using it in forms, however, many users have noticed that the @model.tag_list field deals with comma separated lists of tags, like so:

1
2
# From the README
@user.tag_list = "awesome, slick, hefty"      # this should be familiar

If, in your edit view template, you provide a text field for your users to type in freeform tags, then you will find that your database tables have multiword tags instead of multiple tags. This is less than ideal. Users do not like to type commas.

Build your form like this, and you will see the issue when a user types in “awesome slick hefty” in the input box.

<% form_for([@model]) do f %>
    <div id="model_tags">
	Tags: <%= f.text_field :tag_list %> 		
    </div>
...
<% end %>

You will see this in your DB:

+----+-----------------------------------+
| id | name                              |
+----+-----------------------------------+
|  1 | awesome slick hefty               | 
+----+-----------------------------------+

What you wanted was this:

+----+-----------------------------------+
| id | name                              |
+----+-----------------------------------+
|  1 | awesome                           | 
|  2 | slick                             | 
|  3 | hefty                             | 
+----+-----------------------------------+

The Answer

My workaround involves using a before_filter to unroll the content of the input box, and a compactor method in the edit action to change the internal storage format of acts_as_taggable_on to the format that the user expects. Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ... In the taggable_controller
  before_filter :join_tag_list, :only => [:create, :update]
 
  # GET /users/:id/quotes/1/edit
  def edit 
    @model ||= Model.find(params[:id])
    unroll_tag_list
  end
 
  private
  def join_tag_list
    # Split the tags on spaces and join into comma separated format
    params[:model][:tag_list] = params[:model][:tag_list].split(" ").join(",")
  end
 
  def unroll_tag_list
    # Split the tags on commas and join into a single space separated string
    @model.tag_list = @model.tag_list.join(" ")    
  end

That’s it! Now my users see and work with space-separated tags, and acts_as_taggable_on continues to store comma separated lists internally.

Jul 13

VoteFu is a voting mixin that allows you to extend your models to vote on one another. Largely based on Cosmin Radoi’s acts_as_voteable plugin, VoteFu adds named_scope support, a set of generators to make using the plugin easier, a :polymorphic association to the voting class (so you can have more than one model type perform votes), and some enhancements for Rails 2.1.

I have simplified the code it requires to cast a vote down from three to one. After setting up your models with the proper mixin functionality, you can cast votes like this:

1
2
3
4
5
   voter.vote_for(voteable)
   # OR
   voter.vote_against(voteable)
  # OR
   voter.vote(voteable, [true | false] )

You can also use the old acts_as_voteable sytnax (which will continue to be supported):

1
2
3
4
  vote = Vote.new(:vote => true)
  m    = Model.find(params[:id])
  m.votes    << vote
  user.votes << vote

I hope you find the plugin useful. Comments and feedback welcome. If there is enough demand, I’ll open up a lighthouse project to track issues.

Grab the code from GitHub or visit the VoteFu Page.

May 26

Since I seem to be on a “Comment” and “Terseness” rant, I’d like to point out that I dislike block comments for everything but RDoc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
x ||= ["0"]
=begin
  this is a block comment
  It's good for auto-generated documentation
  , I suppose. 
 
  x.push("1")
 
  But that line of code above might be mistaken 
  for something that executes, if you're not using
  a good IDE with colorization. 
 
=end
puts x.inspect          # ["0"].... NOT ["0","1"]

It’s harder to make that mistake when the code looks like this:

1
2
3
4
5
6
7
8
9
10
x ||= ["0"]
#  this is not a block comment
#
#  x.push("1")
#
#  Now that line of code above shouldn't be mistaken 
#  for something that executes, even if you're not using
#  a good IDE with colorization. 
 
puts x.inspect          # ["0"], just like you'd expect

Given that just about every IDE out there allows you to select a bunch of text and comment it out en-masse, I think the second method works better.

Hopefully, Peter Cooper will forgive me for taking issue with so many of his Ruby Tricks. Most of them are REALLY REALLY GOOD.

May 26

In my post about clever code vs. terse code, I showed some distaste for code that attempts to put a bunch of logical statements on one line. I have a particular coding prejudice that lines of code should be short from left-to-right, if at all possible.

The reason? I like sidebar comments.

Maybe this is my showing my age. Back in the day, we didn’t have widescreen MacBook Pro laptops that could display 600 characters across the screen. (And we liked it! While walking uphill both ways in the snow to school…) Between 17″ CRT monitors and the IDE, I was lucky to get 100 characters across.

So instead of writing long lines of code, I prefer to use a couple extra lines and simplify each discrete statement. Then I will sometimes put comments (aligned with each other) out in the right margin that map to my pseudo-code (which is usually just in my head….I don’t actually write much pseudo-code in Ruby).

For example:

1
2
3
4
5
6
7
8
# Spawn a set of threads to process the queue
1.upto(threadcount) do |thread_id|
  threads << Thread.new(thread_id) do |i| # Each thread
    until @queue.empty?() do                    # grabs an item from the queue
      yield(thread_id, @queue.deq())            # and yields it to the block
    end
  end
end

Some people call this “code smell.” The meaning, I guess, is that if I have to write comments that outline what the code does, the code must be too complicated.

I beg to differ.

Imagine for a moment that you are a fresh-out-of-college programmer, and you open up my codebase to maintain it. You find this:

1
2
# Spawn a set of threads and process the queue all on one line
1.upto(threadcount) { |thread_id| threads << Thread.new(thread_id) { |i| yield(thread_id, @queue.deq()) until @queue.empty?  } }

You might run away screaming after a few dozen lines like that. I sure would. Smaller lines with comments make it easier to follow. And I think sticking them out on the right margin where they don’t interrupt the flow of code makes it easier to ignore them if you’re an experienced programmer who doesn’t need them.

May 26

In 21 Ruby Tricks You Should Be Using In Your Own Code, Peter Cooper outlines some really useful best practices that programmers could benefit from. However, I think that there’s a tendency to over-obfuscate code from time to time in the Ruby world.

I like terse code. I like beautiful code. But I dislike tricky code. For example, let’s look at two tricks Peter Cooper outlines in his post:

Trick #7: Cut down on local variable definitions.

1
2
3
4
5
6
7
 
# Cooper says do this: 
(z ||= []) << 'test'
 
# Instead of this: 
z ||= []
z << "test"

Counting whitespace characters, Cooper’s version of the code is 20 characters long. The second version of the code is 20 characters long. Personally I find the second version easier to read.

Trick #9: 9 - Use ‘and’ and ‘or’ to group operations for single liners.

1
2
3
4
5
6
7
8
9
10
11
# Cooper likes this:
queue = []
%w{hello x world}.each do |word|
  queue << word and puts "Added to queue" unless word.length <  2
end
puts queue.inspect
 
# Output:
#   Added to queue
#   Added to queue
#   [”hello”, “world”]

Hm. While I think this does terse up the code by grouping statements that do a single logical operation onto one line, I think it’s still easier to read this way:

1
2
3
4
5
6
7
8
9
# I like this:
queue = []
%w{hello x world}.each do |word|
  unless word.length < 2 do
    queue << word
    puts "Added to queue" 
  end
end
puts queue.inspect

I think this method makes it easier to modify the discrete elements of the queue operations. For example, I may want to comment out that call to “puts” someday, which would be tougher if I’d used the “and” operator to string it all together on one line. I might also want to add a debug log statement. Again, it gets tough when you’re trying to fit it all onto one line.

My opinion is that finding tricks in the language that allow you to string a bunch of steps onto one line aren’t always the best way to make good code. Sometimes, finding a way to make a set of statements look like a logical unit is a better choice.

May 08

I often have to iterate over a collection and perform some remote, or long running task on each member of the collection.

Threaded Collections is a package for iterating through collections over multiple threads. With large collections, sometimes it can be more efficient to process a collection in parallel, provided that the collected items don’t have a interdependencies, or need to be processed in a specific order.

Usage:

1
2
3
4
5
6
7
8
9
require "threaded_collections"
 
threadcount = 2
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
tps = ThreadedCollectionProcessor.new(arr)
tps.process(2) do |thread_id, item| 
  puts "Thread #{thread_id} processed item: #{item}" 
  sleep 1
end

I abstracted this pattern from a web services client that posted items from a collection, but
each request took a second to process. The remote service had plenty of threads available, so
I parallelized the task with this pattern.

I have no plans to break the interface but I do plan to make two major enhancements:

  1. Make it possible to mix this functionality in to the Ruby iterators, so you don’t have create the ThreadedCollectionProcessor.
  2. Make it work with fibers and processes in addition to threads.

If you want to check it out, you can get the source from the threadedcollections github site.

To install the gem without git:

1
bash# sudo gem install peteonrails-threaded-collections --source=http://gems.github.com
May 07

RESTful applications built with script/generate have a lot of repetitive code. Each generated controller will define default “index” “create” “new” “update” and “destroy” methods that looks similar from controller to controller.

There are at least FOUR plugins that aim to DRY up RESTful controllers each with their own benefits and weaknesses:

  1. make_resourceful - There’s a great Railscast on make_resourceful.
  2. resource_controller Provides a super-class controller that you inherit from. Pretty sweet at handling nested resources…..but don’t confuse it with…
  3. resources_controller — which uses a declarative syntax instead of a superclass. I like seeing “resources_controller_for :foos” in my code.
  4. resource_this — Heavily uses before_filters, if you’d prefer to see things that way.

I am working on a longer, more in-depth comparison of the available frameworks. but I’ve gotta tell you, a “winner” needs to shake out of this list. Having four very strong and useful, but VERY DIFFERENT, ways to DRY up controllers is not beneficial.

Do you remember when there were six ways to Paginate records in a Rails app? Now we use “will\_paginate”, and that’s how it’s done. Everyone knows how to use will_paginate, and it’s terse, well tested, and well supported.

So, which framework do you use? Let me know. I’m interested.