Rails Distributions

A random idea: rails distributions that include what “should be included in the core”. I’m not the first to think of it (google finds several others), but I have been mulling it over lately, and I think it’s a good idea. Nothing too fancy, simply a tarball or gem that includes rails + the stuff that you end up installing every time you set up a real web site with rails. Of course, “what to include” is the big question, so the best thing would be for lots of people to try, and see what sticks. Here’s what I always end up installing:

Acts as Authenticated

Exception Notifier

And I recently found another one that seems to be pretty small, and very handy:

Condition Builder

because I usually always end up having to build up complex queries with dynamic components with any sort of more advanced search, and this makes it much easier, and more fun.

However, I’m sure more advanced Rails users can add to that list. The trick is to nail those things that you pretty much always end up installing sooner or later as your project grows in complexity.

Perhaps at that point a gem could be created that installs them…

Padova Pluto Meeting Talk – Economics of Free Software

A combination of factors worked out rather nicely, and we’ll be spending a long weekend in Padova, where I’ll be giving a talk on the 10th:

http://www.pluto.it/files/meeting2007/programma.html

It should be a fun weekend, and I particularly enjoy this talk and the subject matter. It has a lot of potential for interesting debate and interaction, because it’s not really a “solved problem”.

Missing rails feature: cache everything but this

It’s pretty common to have a front page that has content that is very cacheable, except for a little section with something like “signup” or “my page”, depending on whether the user is logged in or not. It would be very nice to have a handy solution in rails for this problem, which seems to be a fairly common question.

Here’s my stab at an answer:

cache everything but…

However, I’m not entirely happy with it because of the very hacky approach taken to make the render_as_string work – I have to fiddle with an instance variable in the controller:

controller.instance_variable_set '@performed_render', false 

Not good. In the thread linked to above, Paul Gustav posts a link about a system for having two different cached pages, but that’s not entirely satisfying either, because it gets you from 1 version to 2 versions, but going beyond doesn’t look real appetizing.

It would be a very nice problem to solve once and for all with a clean solution.

Simple item-based collaborative filtering with Rails

I suspect there is room for improvements with this, since it is really simplistic, and I certainly am not an expert in the subject. But it works ok for small numbers of items:

def Pair.from_items(items)
  Pair.transaction do
    res = []
    all = items.reject { |i| i.name == "" }.collect { |i|
            i.name.downcase }.sort
    all.collect { |i| ([i]*all.length).zip(all) }.each { |i| 
            i.each {|j| res << j} }
    res = res.each { |i| i.sort! }.uniq.reject { |p| 
            p[0] == p[1] }
    res.each do |pair|
      p = Pair.find(:first, :conditions => 
                            ['val1 = ? and val2 = ?', 
                             pair[0], pair[1]])
      p ||= Pair.new(:val1 => pair[0], :val2 => pair[1],
                     :num => 0)
      p.num += 1
      p.save!
    end
  end
end

Basically what happens is that for a list of items [A, B, C, D], it calculates and inserts into the database that A and B have been purchased/rated/viewed/whatevered together once. Same for A and C, A and D, B and C, and so on. After accumulating enough of these pairs, you can query the datbase for an item – B for instance – and see what it’s been purchased with the most times, and recommend that to people who have shown an interest in B. When someone purchases a group of items togehter, you call Pair.from_items(the_items) and it takes care of inserting the various combinations.

Subversion FAQ: How to make patches utilizing files not in the repository

As kpreid on #svn kindly points out, if you need to make a patch for a subversion project that includes files you have created, you need to add the files:

svn add tests/fixtures/empty.rb

Then you can run svn diff > my_patch.diff, and everything will be included.

Anyone can add files to their working copy, it’s just that they can’t necessarily commit them.

This ought to be in their FAQ.

Airlines and rand()

Ilenia and I are looking for tickets to go “home” (Eugene, Oregon) this summer. We’ve had pretty good luck with Lufthansa in the past (as opposed to Air France, which lost a huge bag of my stuff), so we turned to them first to look for flights. I like the page they have for prices/dates, which gives you a nice way to look around for a better price without stabbing randomly at dates:

Big long Lufthansa URL

However, the maddening thing is that the prices change frequently. Not every day, but often after even 5 minutes! They bounce around up to 100 euro at a time. I understand the theory behind price descrimination, but this is the classic case where the customer ends up feeling like they’re being made fun of and goes elsewhere. United, in our case, which offers a cheaper price for the same plane (they’re Lufthansa’s partner and thus share flights).

ShopList updates

I did some work on my mobile phone shopping list ShopList today.

Thanks to a bug report from Sven Mueller, I think I managed to correct an encoding issue. If you use ShopList and enter non-ascii text into the shoplist web application, let me know if things are working for you.

I also did some work on the back end to enable statistics, but only for users who are logged in to their accounts. Not surprisingly, the most common things people buy at the store are:

  • Milk
  • Bread
  • Butter
  • Cheese
  • Eggs

Which probably hasn’t changed in hundreds of years. Sort of reassuring, I guess?

Domain names vs real estate

I was reading some of the debate regarding this guy and his business:

The man who owns the Internet

and got to thinking about the comparison between domain names and real estate. One of the things that irritates me about domain name squatters is that they can essentially sit on a good name forever, at very, very little cost. You can’t do that in real estate, because you have to pay property taxes, which acts as an incentive to actually do something productive with the property, rather than simply let it sit there until someone comes and offers to buy it from you for even more than you paid. So you can’t let the space go completely to waste – you have a big incentive to at the very least rent it out to someone who can make money with it. You can’t really rent out a domain name, though. Since it’s an integral part of your brand and identity, it would be insane to borrow one for a few years, whereas with a physical business renting space, people will still be able to find you if you move.

Perhaps an annual tax based on the purchase price of domain names would encourage people to either do something valuable with them or pass them on to someone who could? I don’t think anyone would be sad to see pure speculators gone, but on the other hand, I have a strong suspicion that all the extra taxes and red tape would make the idea a net negative, and taxes on ‘real’ domains like google or ebay, would simply be passed on to consumers, and so wouldn’t be desireable.

In any case, it’s something interesting to think about.

mailmodel rails plugin

Here is the first cut at a plugin I created, called Mailmodel. It’s pretty simple, you install it, configure the email sender/destination addresses, and then, in your ActiveRecord objects:

after_save :mail_model

For those objects that you want to be notified of when they change. Think of it as ‘scaffolding’ for email notification of changes in your database (new comments, new users, new payments) when you aren’t quite ready to set up notification for each individual thing.

Available from:

http://svn.dedasys.com/public/mailmodel/

Some improvements that could be made:

  • Customize behavior for some objects: if it’s a this, then include that and that in the object dump.

  • Customized templates depending on object type in order to take the scaffoling analogy further.

Pretty Print Active Record

I wanted to be able to pretty print ActiveRecord objects, and do so in a way that’s a little bit more involved than what pp gives you:

module ActiveRecordPrettyPrint

  def pprint(ar, maxdepth=1)
    pp_helper(ar, "", 0, [], maxdepth - 1)
  end

  private
  def pp_helper(ar, buf, level, seen, maxdepth)
    if level > maxdepth || seen.member?(ar)
      buf << (" " * level) + "#{ar}n"
      return buf
    end

    seen << ar

    reflections = ar.class.reflections
    rcolumns = reflections.collect { |k, v| v.primary_key_name }

    buf << "#{ar.class}:n"
    ar.attributes.keys.reject { |k| rcolumns.member? k }.each do |k|
      buf << (" " * level) + "#{k}  =>  " + ar.send(k).to_s + "n"
    end

    reflections.keys.each do |k|

      buf << (" " * level) + k.to_s + " =>  "
      res = ar.send(k)
      if res.nil?
        buf << "[nil]n"
      elsif res.class == Array
        res.each do |o|
          pp_helper(o, buf, level + 1, seen, maxdepth)
        end
      else
        pp_helper(res, buf, level + 1, seen, maxdepth)
        buf << "n"
      end
    end

    return buf
  end

end

I suspect I’ll fix it up more as I go along, but this is the basic idea… Be careful with maxdepth, though, or else you risk hitting the database too much.