Pretheory.next

June 1, 2008 by

Some people have been wondering what Dan and I are up to these days. For various reasons, we wanted to keep quiet about our new project until now.
We’re currently working hard on Devver, which will provide web-based services for Ruby developers. You can keep up with our adventures on our new Devver blog. Since Pretheory/Seekler is on the back burner for the foreseeable future, we won’t be updating this blog, so be sure to check out our new one.
We’re both really excited about this project and can’t wait to release more details about it as it matures. The really great news for us is that TechStars decided to include Devver as one of its teams for its Summer 08 program. We’re incredibly honored that we were chosen and are super pumped about participating in the program.

Moving on…

April 18, 2008 by

Well, it’s been an incredibly busy month since we last posted on this blog. In addition to coding and pursuing funding, we’ve been thinking hard about our future here at Pretheory.
After a lot of thought, we’ve decided that Seekler, while interesting, is probably not going to be become a viable business for us in the near future. As such, we’ve decided to pursue an entirely new project.
What will happen to Seekler? Our plan is to put it into maintenance mode. We’ll fix critical bugs but won’t be adding any new features for the foreseeable future. We may revisit the project in the far future, but for now, it’ll stay in its current state.
We apologize to those of you who are using Seekler and want us to continue development. We appreciate your support and we don’t make this decision lightly.
But at this point, we feel the best decision is to take all of the lessons we have learned while creating Seekler and pour them into our new venture. This new project is still in stealth mode, but we’ve secured some early funding and have gotten good feedback about the core product. Watch this space for links to more information about this exciting new development.
Finally, I’d like to thank all of our friends, family, and other alpha and beta users who gave us feedback, linked to Seekler, and generally gave us support. We certainly could not made it this far without you.

Finding and Fixing Strange Rails Bugs (or, How I Wasted My Afternoon)

March 13, 2008 by

Rails is a great framework, but sometimes bugs can be incredibly tricky to track down. Case in point, I spent a significant portion of yesterday tracking down a very strange bug. I’ll post the resolution – but perhaps of more general interest, I’ll outline some tips that you can use when tracking down Rails issues (or really, any issues). These tips may be obvious, but sometimes in my desire to quickly fix a bug, I forget the most basic rules of debugging.
Short Story: Ruby Classifier requires ‘mathn’. As it turns out, requiring ‘mathn’ breaks redirect behavior in Rails. Check out Rails ticket 5433 for more info and a workaround.
(Very) Long Story:
The initial behavior I noticed was that one integration test was failing. The integration test was doing the following


post_via_redirect '/account/login', options
assert_response :success

And was failing with the following error:
Expected response to be a , but was <302>
Not so weird in itself, but the bug only appeared when I ran the tests using autotest. When I ran the test via rake test:integration, everything worked. I looked at the test and the controller and everything seemed normal (and I hadn’t changed anything in the test or in the controller lately), so I started to dig in deeper.
Tip 1: Isolate the changes. My first step was to use svn to track down the exact revision that had caused the bug (I hadn’t caught the bug before checking in because I had been testing using rake, not autotest). Luckily, this is pretty simple – just keep performing svn update -r REVISION_NUM and running the test until you find the revision that causes the test to fail (I wish I had a tool to do this automatically…).
However, in my laziness, I’d forgotten to …
Tip 2: Minimize the Repro. This really should be tip 1, but I’m telling this story chronologically, so you can learn from my mistakes. As I said, this bug only reproed when using autotest. Each time I wanted to test for the bug, I had to wait almost a minute for autotest to run the tests. Due to this long repro, I ended up spending probably ten times the amount of time I needed to figure out which checkin caused the bug.
Usually, when a test fails, you can just use ruby to run a single test. But if you ever have a bug that only seems to repro in autotest, remember that autotest prints out all the commands it runs. In this case, it was simply a case of copying and pasting the code (which ran a ton of test files) from the output of autotest onto the command line. It looked something like this:


ruby -I.:lib:test -rtest/unit
-e "%w[test/functional/resources_controller_test.rb
test/functional/account_controller_test.rb test/unit/merge_test.rb
test/unit/render_state_test.rb test/integration/filter_clears_test.rb
test/unit/item_test.rb test/functional/admin_items_controller_test.rb
test/unit/comment_test.rb test/unit/lists_helper_test.rb
test/functional/lists_controller_test.rb test/functional/items_controller_test.rb
test/unit/list_test.rb test/unit/memory_list_test.rb
test/integration/contact_form_test.rb test/unit/xpath_test.rb
test/functional/contact_controller_test.rb test/unit/resource_test.rb
test/unit/membership_test.rb test/unit/list_classifier_test.rb
test/functional/listgroups_controller_test.rb test/integration/resources_test.rb].each
{ |f| require f }" | unit_diff -u

Yikes. That successfully reproed the bug, but it took way too long. The next step was manually pulling out test files until the bug stopped reproing. That left me with a simpler (and much faster) repro:
ruby -I.:lib:test -rtest/unit -e "%w[test/unit/list_classifier_test.rb test/integration/resources_test.rb].each { |f| require f }"
OK, so it seemed that there is some weird interaction between list_classifier_test and resources_test.
Tip 3: Simplify, Simplify This is really an extension of tip 2, but I’m repeating it because most of debugging is systematically simplifying the problem by removing complicating factors. So, I went to list_classifier and commented out all the tests. The bug disappeared. I put a single test back in – the bug reappeared.
Now I was onto something. I then realized that loading the file under test (list_classifier.rb) was the problem. That code is based on the awesome Ruby Classifier library. As a result, the file begins with require 'classifier'. Interesting. So I tried just requiring ‘classifier’ in the integration test. Bingo. Somehow, using the Classifier library was breaking my integration test.
Tip 4: Follow your gut, but validate. For nasty bugs like this, the interactions are so complicated it would take forever to just step through the code and find the bug. So, you have to develop a gut feeling for what might be causing the bug and follow that first. Of course, you have to develop tricks to quickly confirm or reject your hunches so you don’t go down the wrong path for an hour.
For instance, my initial feeling was that monkey patching was to blame. Specifically, I noticed that both Classifier and Rails had defined a ‘sum’ method on Array (actually, Rails defines ‘sum’ on Enumerable, but Array includes Enumerable). A quick check confirmed that Classifier’s ‘sum’ had overwritten Rails’ ‘sum’ by the time my integration test ran. But I wasn’t sure if the Rails code actually ever called this method.
To check this, I used ruby-debug. I first set a breakpoint right before the troublesome line in the integration test. At the debugger prompt, I turned on trace mode (trace on all) and then continued (c). Trace mode prints out every single line of code that is executed, including the file in which the line appears. It was simple enough to copy/paste the trace into Emacs and search for any line executed in the ‘classifier’ library.
As it turns out, I didn’t find anything. My hunch was wrong – Classifier’s ‘sum’ method wasn’t to blame. But luckily, it didn’t take me too long figure it out.
So, I went back to simplifying the repro. Instead of doing require 'classifier' (which includes the whole gem), I started including specific files from the gem. After doing this for awhile, I found that only requiring the file ‘classifier-1.3.1/lib/classifier/extensions/vector.rb’ caused the bug.
I tried to simplify even more. That file starts with both require 'matrix and require 'mathn'. Could one of those be the problem? I tried requiring each of those files at the top of the integration test and sure enough, require 'mathn' caused the problem.
Tip 5: Google is your friend. All throughout this long process, I’d been Googling to see if anyone had solved this issue. Of course, until the end I didn’t really know what the root cause was, so my searches turned up nothing useful. However, after narrowing it down to integration tests and mathn, I found a this Rails ticket (search ‘rails integration test mathn’). As it turns out, mathn changes the behavior of integer division, which makes the code return the wrong HTTP status code. And the reporter includes a simple, one-line patch which is easy to apply.
In retrospect, it all seems to simple (and in fact, it’s frustrating that it took me so long to solve). When tracking down a bug, it’s very easy to get frustrated or overwhelmed with the sheer size of the search space and forget basic debugging practices. Although tracking down bugs will always remain somewhere between science and art, these tips should help you the next time you encounter a real head-scratcher.

Rails: Completing Requested Action After Authentication

February 26, 2008 by

Within Seekler, we have several actions that are only available to logged-in users. We wanted a general solution that would first redirect the user to login or create an account and then complete the action the user initially requested. The primary motivator for this was non-logged-in users clicking ‘create your own list’ on a Seekler list. If a user clicked this link, we wanted to allow them to login or register and then have the list creation action take place and return them to their newly created list. We had other cases of site actions, that also required being logged in, so I was hoping to find a simple way to do this across the site.
We use the acts_as_authenticated plugin (I know most people are now using restful_authentication, we haven’t switched yet), which relies on before_filters to verify users are logged in before using logged-in-only actions. I ended up just adding one line into that system that makes it simple to return the user to his or her previous action after logging in.
In a controller using acts_as_authenticated, there is normally a before_filter requiring authentication before any actions except the actions available to all visitors

before_filter :login_required, :except => [ :show, :list]

This means that on an action like :create the user will end up calling the login_required method in /lib/authenticated_system.rb. If you add the following line to that method, it will record the information you need to redirect the user back to the action they intended after they login.

def login_required
username, passwd = get_auth_data
self.current_user ||= User.authenticate(username, passwd) || :false if username && passwd
session[:last_action] = request.env['REQUEST_URI'] unless logged_in? && authorized? # add this line!
logged_in? && authorized? ? true : access_denied
end

At this point, the filter will direct all non-logged-in users to your associated login failure action, in our case /account/login
In the login action, (after doing any other login specific code) you just have to redirect the user if they have :last_action set

def login
# login stuff
if session[:last_action]
redirect_to session[:last_action]
else
redirect_to :controller => 'account', :action => 'index'
end
end

You can add a bunch of other things like ignoring certain actions you don’t want to forward the user to, or also return the user to wherever they were before clicking a login link, but this simple version gives the basic idea. Obviously this code is specifically for the acts_as_authenticated plugin, but it should be relatively easy to generalize this same sort of solution to work for any type of authentication that is in use on your Rails project.
If you want to see this in action, just visit a list like Best Charities on Seekler and click the ‘create your own list’ link in the top right.

The Maybe Monad in Ruby

February 14, 2008 by

| [tests]
I’m a little behind on my goal to learn a new programming language each year – I’m still working on really understanding last year’s language, Haskell. Judging from the number of tutorials online, understanding monads is one of the hardest parts of learning Haskell.
I won’t even try to explain monads to you, because (as this post will reveal), I’m still a bit shaky on them myself. However, I will say my attempts to build a Maybe monad in Ruby have helped me learn more about Monads – and have yielded a pretty useful piece of code.
Why should you care about the Maybe monad?
Have you ever written code like this?

if(customer && customer.order && customer.order.id==newest_customer_id)
# ... do something with customer
end

Don’t you wish there was just a way to call customer.order.id without all those intermediate checks for nil objects?
One solution is to obey the Law of Demeter – in other words, to change the call to customer.order_id. Two problems – one, sometimes obeying the LoD is more work than its worth (especially for quick and dirty solutions) and two, it still doesn’t help you if customer is nil.
Still not convinced there is a problem worth solving here? Check out better explanations by Oliver Steele or Reg Braithwaite – they explain the problem better than I did (and present some interesting solutions).
Anyway, here is my solution – a Maybe monad in Ruby. You would change the above code to:

if(Maybe.new(customer).order.id.value==newest_customer_id)
# ... do something with customer
end

How does this work? Without going into too much theory about monads, the basic idea is that Maybe is a container object. It stores (or ‘wraps’) any value and then controls how methods are called on the wrapped object.
More concretely, the call to Maybe.new wraps a value in a Maybe object. Whenever you call methods on the Maybe object, it does a simple check: if the wrapped value is nil, then it returns another Maybe object that wraps nil. If the wrapped object is not nil, it calls the method on that object, then wraps it back up in a Maybe object.
Confused? Here’s a few examples:

>> Maybe.new("10")            # => #<Maybe:0x34cbd5c @value="10">
>> Maybe.new("10").to_i       #=> #<Maybe:0x34c919c @value=10>
>> Maybe.new("10").to_i.value #=> 10
>> Maybe.new(nil)             #=> <Maybe:0x34c4408 @value=nil>
>> Maybe.new(nil).to_i        #=> #<Maybe:0x34c2644 @value=nil>
>> Maybe.new(nil).to_i.value  #=> nil

I’ve started to use this in my code on Seekler and it’s definitely helped me clean up some messy conditional code quite a bit. Try it out and please let me know if there is any way I can improve it. You can find the source code here. You can also check out the tests.
All in all, this project was a lot of fun, helped me understand monads better, and showed me how a powerful concept from Haskell can be a very useful concept in Ruby.
Update: Thanks to the help from people commenting on this post (as well as some help from James Iry), I think I’ve solved the problem I describe below. It turns out I was confusing two different methods that monads should have: fmap (which takes any function and applies it in the monad) and pass (which takes a function that returns a Maybe and applies the wrapped value to it). I’m leaving the issue below in the hopes that others who may be confused can learn from it.
There is one big problem with my code (and it reveals my ignorance regarding monads): this monad doesn’t seem to meet the third monad law. In other words, the following test fails

  def test_monad_rule_3
f = Proc.new {|x| x*2}
g = Proc.new {|x| x+1}
m = Maybe.new(3)
assert_equal m.pass{|x| f[x]}.pass{|x|g[x]}.value, m.pass{|x| f[x].pass{|y|g[y]}}.value
end

I learned about the monad laws from ‘Monads on Ruby’ on Moonbase, but I don’t yet understand how the third monad law works (in his examples at the bottom of this page). If any wise Ruby hacker (or Haskell hacker) can help me bridge this gap in my understanding, I’d really appreciate it.
For the interested reader, there’s some great information out there about this problem in general and Ruby monads in particular.
MenTaLguY has a great tutorial on Monads in Ruby over at Moonbase
Oliver Steele explores the problem in depth and looks at a number of different solutions
Reg Braithwaite explores this same problem and comes up with a different, but very cool solution in Ruby
Weave Jester has another solution, inspired by the Maybe monad
Update: James Iry has a great explanation of monads from the Scala perspective. His explanation of the monad laws (and the difference between map and flatMap, as they are called in Scala, really helped me out)

Capistrano path and environment variable issues

February 12, 2008 by

We have been using Capistrano for awhile now and it has been working great. Recently, for reasons we are not sure of, migrations started failing. When we executed ‘cap deploy:migrate’, we would get an error “no such file to load — rcov/rcovtask”. After a lot of investigation, I found that this meant that the system, for whatever reason, couldn’t find our gems anymore.
Since Capistrano hardly gives any information when failing, it took awhile to figure out what was going on. sshing in as our Capistrano user, and running printenv, showed that the environment variables for the Capistrano user were all set as expected. After some investigation, we learned that since Capistrano runs a non-interactive user, the environment isn’t set up the same. To figure out the environment that Capistrano was running as, I created a task and added it to config/deploy.rb

desc "Echo environment vars"
namespace :env do
task :echo do
run "echo printing out cap info on remote server"
run "echo $PATH"
run "printenv"
end
end

After saving your deploy.rb file you should be able to execute that command on your servers by running “cap env:echo”.
This printed out a different path than sshing in as our Cap user and also was missing the RUBYOPT=rubygems environment variable. Obviously, not having RUBYOPT set was causing the problem of not finding out gems.
So next, we just had to set up the correct environment for the non-interactive Cap user. This was a little tricky since non-interactive users don’t load all the environment settings like normal users. This is done for extra security. Unfortunately, it means it is a little more annoying to set up these variables, and not as well documented.
If you need to add environment variables or change the PATH for a non-interactive user, you need to edit two files. First ssh in as the user under which the non-interactive scripts will be run. Then, in that user’s home directory, create a file ~/.ssh/environment (in our case /home/cap/.ssh/environment). Edit this file and add whatever environment variables you need (in our case RUBYOPT=rubygems), and save the file. Then edit /etc/ssh/sshd_config, and add the following line
PermitUserEnvironment yes
I would run ‘man sshd_config’ to make sure your version of sshd supports this option, as some older versions and distros (we are using Debian) do not. Then restart ssh by running “sudo /etc/init.d/ssh restart”. At this point, you should try running “cap env:echo” again, which should print the RUBYOPTS environment variable set correctly. This fixed our problems and migrations began running again without a problem.

A New Resource For Colorado Entrepreneurs

February 6, 2008 by

For the months before we launched Seekler, we were basically holed up in our house, coding night and day. Since we launched, we’ve been making an effort to engage more with the local entrepreneur community. What we’ve found is that this area (Boulder in particular, but Denver as well) has a great ecosystem for tech startups.
Some of our friends in this community recently came up with a great idea – to try and collect all of the knowledge that tech entrepreneurs need to get started in one place – stuff like recommendations on lawyers, accountants, banks, events, health insurance, etc.
This made a lot of sense to us – after all, we spent a lot of time getting Pretheory up and running, precisely because we didn’t have such a resource. And setting up the nuts and bolts of a company is pretty boring – you want to do that stuff as quickly as possible, so you can get to the interesting part – building a technology that people will love.
So, if you’re in the Denver/Boulder area and are looking to found your own startup, I encourage you to check out the Boulder Tech Bootstrap. If you are already up and running, I encourage you to go add some information to help others.
We’ve added some info to the site – and we also have created a few lists that we hope Colorado tech entrepreneurs will find useful. Check them out and let us know if they help you!
Best Boulder/Denver Startup Blogs
Best Startup Events in Boulder/Denver, CO
Seed Funding Opportunities (ideally, we’d like you to stay in the area, but you should explore all your options for funding…)

Seekler’s top 10 reviewers

February 5, 2008 by

Seekler added the ability to add full reviews to items you rank awhile ago. Only recently have we been showing off this feature, and making it obvious to the users. It has been popular for users to read reviews about the items ranked on our lists. So as a little thank you to our users that have started adding reviews, I present the top ten users with the most reviews on Seekler.

  1. dan
  2. ben
  3. michaelwong38
  4. peter
  5. vacelts
  6. DomFilosa
  7. galactic_dev
  8. drew.klein
  9. nicole
  10. Jezebel

Congratulations, and thanks for your time and reviews, keep up the good work.

Creating Super Bowl Lists in Real Time at Seekler.com

February 3, 2008 by

Today we’re trying something new at Seekler – we’re creating a list of the best Super Bowl commercials of 2008 in real-time while we’re watching the game. If you want, feel free to join us and create your own list of favorite commercials as you watch the big game!
We’ve also got a list of the best Super Bowl commercials of all time that you can vote on as well. Check it out!

Good news for Seekler

January 22, 2008 by

We have always known that consumer opinions about products and services was an interesting and profitable area to be in. For example, according to some recent statistics in Entrepreneur magazine*:
“62% of shoppers read consumer-written product reviews online.
80%+ say their purchase decisions have been directly influenced by reviews.
70% of shoppers share product reviews with their friends, family, or colleagues.
18% of consumers say they look for more product information online or in other locations in addition to on the product’s packaging.”
Since Seekler’s community-built lists provide an incredibly easy way for shoppers to find and share their opinions about products, this means that
62% of shoppers could be looking at Seekler lists.
80%+ could have their purchase decisions influenced by Seekler lists.
70% of shoppers could be sharing their lists with friends, family, and the whole Seekler community.
18% of consumers could find product information at Seekler.
We know that’s we’re a tad bit optimistic, but it just goes to show how many people are using existing review sites and could find new products and services more quickly and easily by using Seekler.
*February 2008 issue, page 26, source of stats not cited


Follow

Get every new post delivered to your Inbox.