ActiveRecord count vs length vs size and what will happen if you use it the way you shouldn’t

One of the most common and most deadly errors you can make: using length instead of count. You can repeat this multiple times, but you will always find someone who’ll use it the way it shouldn’t be used.

So, first just to make it clear:

#count – collection.count

  • Counts number of elements using SQL query (SELECT COUNT(*) FROM…)
  • #count result is not stored internally during object life cycle, which means, that each time we invoke this method, SQL query is performed again
  • count is really fast comparing to length
2.1.2 :048 > collection = User.all; nil
 => nil
2.1.2 :049 > collection.count
   (0.7ms)  SELECT COUNT(*) FROM `users`
 => 16053
2.1.2 :050 > collection.count
 => 16053

#length – collection.length

  • Returns length of a collecion without performing additional queries… as long as collection is loaded
  • When we have lazy loaded collection, length will load whole colletion into memory and then will return length of it
  • Might use all of your memory when used in a bad way
  • Really fast when having a eagerly loaded collection
2.1.2 :055 > collection = User.all; nil
 => nil
2.1.2 :056 > collection.length
  User Load (122.9ms)  SELECT `users`.* FROM `users`
 => 16053
2.1.2 :057 > collection = User.all; nil
 => nil
2.1.2 :058 > collection.to_a; nil
  User Load (140.9ms)  SELECT `users`.* FROM `users`
 => nil
2.1.2 :059 > collection.length
 => 16053
2.1.2 :060 > collection.length
 => 16053

#size – collection.size

  • Combines abilities of both previous methods;
  • If collection is loaded, will count it’s elements (no additional query)
  • If collection is not loaded, will perform additional query
2.1.2 :034 > collection = User.all; nil
 => nil 
2.1.2 :035 > collection.count
   (0.3ms)  SELECT COUNT(*) FROM `users`
 => 16053 
2.1.2 :036 > collection.count
   (0.3ms)  SELECT COUNT(*) FROM `users`
 => 16053 
2.1.2 :037 > collection.size
   (0.2ms)  SELECT COUNT(*) FROM `users`
 => 16053 
2.1.2 :038 > collection.to_a; nil
  User Load (64.2ms)  SELECT `users`.* FROM `users`
 => nil 
2.1.2 :039 > collection.size
 => 16053 

Why would you even care?

Well it might have a huge impact on your apps performance (and resource consumption). In general if you don’t want to care at all and you want to delegate this responsibility to someone else, use #size. If you want to care, then play with it and understand how it works, otherwise you might end up doing something like this:

print "We have #{User.all.length} users!"

And this is the performance difference on my computer (with only 16k users):

       user     system      total        real
count     0.010000   0.000000   0.010000 (  0.002989)
length    0.730000   0.060000   0.790000 (  0.846671)

Nearly 1 second to perform such simple task. And this could have a serious impact on your web app! Keep that in mind.

Ubuntu 14.04 Gnome keyring (Seahorse) auto unlock when auto login

Seahorse doesn’t unlock your keyring when you have auto login enabled. The funny thing is that even if you set up an empty password, you will still have to unlock it manually. Maybe it’s a bug, maybe it’s a security feature. Either way, if you have an encrypted LVM like I do, and you shutdown your computer when you don’t need it having to unlock keyring each time can be a real pain in the ass. First you need to unlock whole system, then you skip login (because of the auto login), but you still need to unlock keyring.

Luckily there’s a really simple solution to this:

Change your keyring password

First, you need to change your keyring password. Use unique pass-phrase that you don’t use anywhere else because it’s going to be stored in plain text. To do this, press ALT+F2, type seahorse and press enter. You will see following window:

keyring1

Go to View and select By keyring. You should see something like this:

keyring2Right click on Login Keyring (the first one) and Change password. Then just provide an old one (should be the same as you account password) and a new one.

Create a simple Python script

Now you have a new keyring password. To unlock it automatically, we will use a simple Python script, that will be executed each time you are auto logged in:

#!/usr/bin/python

import gnomekeyring
gnomekeyring.unlock_sync(None, 'your keyring password');

save it as a hidden file somewhere in your home directory (I used ~/.keyring).

Now add executing rights:

chmod +x ./.keyring

You can also execute it to check if it’s working:

[~]$ ./.keyring 

If it doesn’t you will see an error explanation:

[~]$ ./.keyring
Gkr-Message: secret service operation failed: The password was invalid
Traceback (most recent call last):
  File "./.keyring", line 3, in <module>
    gnomekeyring.unlock_sync(None, 'PyGaCQbiacPUPgFcJrwjIsEcz');
gnomekeyring.IOError

Add your keyring script to autostart (auto startup)

Just ffollow this article and in a command field put: /home/mencio/.keyring

That’s all. After that, you should have automatically unlocked keyring after your auto login.

15
Sep 2014
POSTED BY
POSTED IN Linux
DISCUSSION 0 Comments