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.
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:
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!
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.
Pretty neat methods, aren’t they?
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
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
You can also use
many? to check the existence of a model, named scope, association, or relation:
and the result will be either
Worth mentioning are
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
exists? can be used on collections (
ActiveRecord::Base classes or relations), and
new_record? on single records (
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
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? 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
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
To simplify it (as it’s not very beginner-friendly):
present?is equal to
blank?is equal to
respond_to?(:empty?) ? !!empty? : !self(what we know from documentation linked some way up)
empty?is a method valid only for arrays, strings, and hashes.
ActiveRecord::Baseclass is neither of them, so the result is
!blank?, the final result is
!!self, what equals
self, what eventually counts as
falseymean non-boolean value treated as
false, and in Ruby only
falsey. Everything else is truthy (yes, even 0 is truthy))
- And that’s why calling
present?on class always results with
At some point the difference between
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.
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.
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(: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
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.
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:
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
maximum methods, respectively:
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
All above calculation methods (
sum) work on a model, relation, and more complex chains -- just like
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:
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