Blog
13.07.2016Marcin Pakuła

Active Record - brief introduction for beginners

When creating an app in Ruby on Rails, from the very beginning, on every single step of your developer's journey, you're going to use ActiveRecord methods. Lots of them, and frankly speaking, it's good to know them well (if not by heart).

Despite almost everyone uses AR methods to develop almost every app, there are still many methods which are not widely known. Many of them can save your time (and to be honest, sometimes even your nerves) and keep your code nice and clean. Below you can find some useful examples, which are good to be familiar with.

Querying

If you want to query a single or multiple columns from a model, pluck comes to help. Accepting a list of column names as arguments, returns an array of values of the specified columns:

Thanks to that, it makes possible to replace code like:

or

or

with

or

However, pluck converts a database result into a Ruby Array directly. This can lead to a better performance for large queries, but any model method overrides will not be available -- you have to keep it in mind!

What's more, pluck triggers an immediate query. Meaning, it cannot be chained with any further scopes (but it works with previously constructed ones):

There’s also another method -- ids -- which can replace pluck, as it does exactly the same work: plucking all the IDs for the relation using the table's primary key.

or

Pretty neat methods, aren’t they?

Presence

When it comes to checking existence of an object, there are some handy methods. Let’s start with exists?. It works in a similar way as find, but instead of returning an object (or collection of objects) it will return either true or false.

This method also takes multiple values, and will return true if any of those records exists.

And to check whether table is empty or not, you can always write

and got false or true, accordingly.

You can also use any? and many? to check the existence of a model, named scope, association, or relation:

and the result will be either true or false.

Worth mentioning are persisted? and new_record? methods, too. The first one returns true if the record is persisted, meaning it is not a new record and it was not destroyed, and false otherwise. The latter returns true if the object has not been saved yet (a record for the object does not exist in database), otherwise returns false.

Important note: exists? can be used on collections (ActiveRecord::Base classes or relations), and persisted? and new_record? on single records (ActiveRecord::Base instances).

exists? (& any?) vs. present?

At an early stage of coding when your app is relatively small, if you want to check whether something in your database is present or not, you could use method present? (what is, somehow, intuitive but not necessarily correct). But as your application grows and your database becomes more and more loaded with records, the time difference needed for execution of methods exists? and present? grows as well.

It's due to the character of those methods -- exists?, as an ActiveRecord method, will stop when it finds the first record (and return a boolean value); you can also use any? method, which works in a slightly different way (when called, it executes SELECT COUNT(*) FROM instead of SELECT 1 AS one FROM like exists? does, therefore it takes more time). On the other hand, present?, as an extension to an Object, will load all records from the table (and initialize model’s instance for each present record).

Generally speaking, in this case there are two main issues with present? method. For relation it’s defined as !blank?, and blank? as to_a.blank? (blank? method is opposite to present?: it will return true if an object is blank (i.e. false, empty, or a whitespace string), and false if not). This to_a chunk extracts all records from the database which falls into our criteria. The first issue to deal with is the time needed to do so -- more records mean more time. The latter one is time and memory needed to create an ActiveRecord Object of each one: in some border cases we could use ALL available memory (what is a very big problem, obviously).

You need to be cautious with present? because of one more reason, too. You can be surprised (not in a positive way), when you try to use present? on ActiveRecord::Base class. User.present? will return true regardless of whether there are records in users table or there are not. This is because present? method, as we saw above, is defined only for ActiveRecord::Relation and not for ActiveRecord::Base.

To simplify it (as it’s not very beginner-friendly):

  1. present? is equal to !blank?
  2. blank? is equal to respond_to?(:empty?) ? !!empty? : !self (what we know from documentation linked some way up)
  3. empty? is a method valid only for arrays, strings, and hashes. ActiveRecord::Base class is neither of them, so the result is !self
  4. As present? equals !blank?, the final result is !!self, what equals self, what eventually counts as truthy argument (truthy and falsey mean non-boolean value treated as true or false, and in Ruby only false and nil are falsey. Everything else is truthy (yes, even 0 is truthy))
  5. And that’s why calling present? on class always results with true

At some point the difference between exists? and present? becomes really significant: Let’s check the case of 1500 records:

Not bad, hmm?

Execution in case of 60000 records:

Ok, it took some time, but still -- it's not like really, really bad, right?

But how about database with 500000 records?

Ouch. So, yes, it's important to know the difference.

Calculations

In many cases you will encounter a necessity to calculate something, like number of products in your basket, range of users' age, or average value of clients' orders. And there are few useful methods for doing that, waiting to be used.

But: use them with care! They DO NOT sanitize raw SQL arguments and are not intended to be called with unsafe user input. If you are not cautious enough, your mistake can open up code to SQL Injection exploits, which you obviously DON’T want to happen.

count

Method which (not surprisingly) counts the number of whatever you want to count. Works on a model, relation, or even in more complicated chains:

What is worth to notice, count and count(:id) differ slightly when it comes to SQL queries (as shown below). Member.count returns the total count of all members in your database, and Member.count(:id) returns the total count of all members in your database whose ID is present in database (i.e. all records where ID is not NULL).

Bear in mind that the latter one might be slower, though: just the number of rows in this table has been already cached, and :id column is not defined as NOT NULL -- hence there can be some NULL values in it and so MySQL have to perform full table scan to find out. (important note: it’s true for MySQL but not necessarily for other DB’s, and for sure not for PostgreSQL)

There’s also one more way to count something in your database: .count(1). But as “1” is a non-null expression, it's the same as COUNT(*). The optimizer recognizes it for what it is: trivial.

average

If you want to see, for example, the average value of your clients' orders, you can call average method on the class that related to the table:

minimum & maximum

If you want to find a minimum or maximum value of a field (let's say, your Users' age) in your table, you can call minimum and maximum methods, respectively:

sum

If you want to find a sum of a field for all records in your table (for example, likes for a blog posts) you can call sum method:

All above calculation methods (average, minimum, maximum, and sum) work on a model, relation, and more complex chains -- just like count.

group

There’s also one more method which might save you a lot of time (or at least simplify your life a bit) -- group. For example, if you want to check rating of your products, or views count of your posts, you can extract it one-by-one. But you could always group it and got the result more efficiently, as shown below:


Summary

To wrap it up -- methods described in this post might help you with your application when it comes to calculate something, query it, or check presence of specific records in your database. But they are just a mere fraction of what ActiveRecord offers. There's a bunch of handy solutions, which are (sadly) not very wide-known – so we highly recommend you to benefit from it!

photo from: unsplash.com

Check our latest product - it's based on our experience of managing over 50-people strong company. The tool we're missing as a small company and not an enterprise.

humadroid.io is an employee and performance management software. It's an unique tool allowing everyone to be in the loop - by having up to date info about co-workers, time-off, benefits, assets, helping with one-on-ones, being a go-to place for company-wide announcements.

Check out humadroid.io
Top

Contact us

* Required fields

The controller of your personal data provided via this contact form is Prograils sp. z o.o., with a registered seat at Sczanieckiej 9A/10, 60-215 Poznań. Your personal data will be processed in order to respond to your inquiries and for our marketing purposes (e.g. when you ask us for our post-development, maintenance or ad hoc engagements for your app). You have the rights to: access your personal data, rectify or erase your personal data, restrict the processing of your personal data, data portability and to object to the processing of your personal data. Learn more.

Notice

We do not track you online. We use only session cookies and anonymous identifiers for the purposes specified in the cookie policy. No third-party trackers.

I understand
Elo Mordo!Elo Mordo!