Code heroku ruby

Find the total number of rows in your Rails app.

Heroku have just introduced a limit on their free database of 10,000 rows. As their robots convert each of their Rails 3 apps to a new database architecture, any database approaching 10,000 rows will send out an email warning the user.

Mine came today:

The database HEROKU_POSTGRESQL_BRONZE_URL on Heroku app XXXXX is approaching its allocated storage capacity.

The database contains 8,387 rows. The  plan allows a maximum of 10,000 rows.

It encourages the developer to upgrade to the a Basic database. (Bronze above refers to a label on the database, not the current type of database).

To get around that row limit I compressed an old table by removing some no-longer-required receipt records from the database and saved about 2700 rows. But how do I programmatically check the total number of rows that remain in the database now?

First, get the collection of ruby Models available in the application

ActiveRecord::Base.send :subclasses

Then we can loop over them, take a subtotal and output it to our command line.

ActiveRecord::Base.send(:subclasses).each do |sc| 
    st += sc.all.size
puts "Total number of rows is #{st.to_s}"

Or in a one liner:

st=0; ActiveRecord::Base.send(:subclasses).each {|sc| st += sc.all.size}; puts "Total number of rows is #{st.to_s}"

Update to this post

I recently added a non-ActiveRecord class (via the gem ‘slugged’) to my application. It means that the “sc.all” call fails, as “Slugged::Slug resolves to a string “Slugged::Slug(Table doesn’t exist).”

One way to work around this is to add in a try/catch block, which in Rails looks like this:

// do something
rescue ActiveRecord::StatementInvalid
// response

or in our shorthand example looks like this:

st=0; ActiveRecord::Base.send(:subclasses).each {|sc| begin; st += sc.all.size unless sc.all.nil?; rescue ActiveRecord::StatementInvalid; end; }; puts "Total number of rows is #{st.to_s}"

If anyone has a better, more Railsy, way of doing this I’d love to hear it. Unfortunately sc.class resolves to “Class” in this case, and not String or Object so I can only respond to the exeception.