views:

28

answers:

1

I have an ActiveRecord::Base class which needs to have one field's value picked as the lowest integer available considering the records already in the database. This snippet does that, does it seem efficient to you? Can it be improved?

class Thing < ActiveRecord::Base
  def initialize
    special = 0
    Thing.find(:all,:order=>"special ASC") do |s|
      break if s.special.to_i != special
      special += 1
    end

    super
    write_attribute(:special,special)
  end
end
+1  A: 

You should overrride after_initialize in your class instead of initialize. Overriding initialize doesn't always work as expected.

As for automatic value generation, I think the best option would be to use an auto-increment column in the database, because I'm not sure how you would deal with concurrency issues otherwise. This would result in gaps in the used values when rows are deleted of course, so I don't know if that's going to work for you.

Alex - Aotea Studios
The gaps are a requirement -- the project is analogous to a URL shortner where the short URLs expire after a while - I realise that specific concept is retarded, but you get the gist of the reason behind there being gaps! However you are right to bring up concurrency, unless I were to do a `self.save` immediately after my `write_attribute` line above, thereby preventing the next instance of the class from using the same `special` - thoughts? Your tip about `after_initialize` is also an excellent one - thanks!
JP
wrt the concurrency, I decided I don't really need to know my 'special' value while I'm creating records, so I put the whole of the above `initialize` function (minus the `super`) into one I access `before_save`. Thanks so much!
JP
I think you'll still have concurrency issues with this solution. Consider what happens when two processes start executing that code at once - they both end up choosing the same `special` value and then both write it back to the database. I think you'll need to implement some sort of a lock.
Alex - Aotea Studios
Poopsticks. I just managed to get the same value for `special` in 5 separate rows by running my test script multiple times in quick succession (by hand!) - I think I'll have to look into locking the database?
JP
Ha, good timing :P
JP