Active Record Flashcards

1
Q

What is Active Record?

A

Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database. It is an implementation of the Active Record pattern which itself is a description of an Object Relational Mapping system.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is the Active Record Pattern?

A

In Active Record, objects carry both persistent data and behavior which operates on that data. Active Record takes the opinion that ensuring data access logic as part of the object will educate users of that object on how to write to and read from the database.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Active Record as an ORM Framework

A

Represent models and their data.
Represent associations between these models.
Represent inheritance hierarchies through related models.
Validate models before they get persisted to the database.
Perform database operations in an object-oriented fashion.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

How do we create Active Record Models?

What is an example?

A

Subclass the ApplicationRecord:

class Product < ApplicationRecord 
end

This will create a Product model, mapped to a products table at the database. By doing this you’ll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. Suppose that the products table was created using an SQL statement like:

CREATE TABLE products (
   id int(11) NOT NULL auto_increment,
   name varchar(255),
   PRIMARY KEY  (id)
);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Describe ActiveRecord::Base

A

Application Record inherits from ActiveRecord::Base, with has many methods:
.table_name
.set_fixture_class

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What are some typical AR methods?

A

.where .select .joins .order .limit

** REMEBER to pass in symbols of tablenames an not strings **

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is an N+1 Query? (aka N+1 Selects)? And how do we use ‘includes’ or ‘joins’ to make it faster?

A

N + 1 query is when a query is performed once for each request. Each db query had overhead. so this can be very wasteful.

includes prefetches the association comments, so it doesn’t need to be queried for later. includes does not change the type of the object returned (in this example, Posts); it only prefetches extra data. It still run in the similar amount of time but it doesnt hit the DB.

We use includes when we need to prefetch an association and use those associated records. If we only want to aggregate the associated records somehow, includes is wasteful, because all the associated records are pulled down into the app. For instance, if a User has posts with many, many comments, we would pull down every single comment. This may be more rows than our Rails app can handle. And we don’t actually care about all
the individual rows, we just want the count of how many there are.
When we want to do an “aggregation” like summing the number of records (and don’t care about the individual records), we want to use joins.

joins # joins can be surprising to SQL users. When we perform a SQL join, we expect to get “wider” rows (with the columns of both tables). But joins does not automatically return a wider row; User.joins(:comments) still just returns a User. In this sense, joins does the opposite of includes. includes fetches the entries and the associated entries both. User.joins(:comments) returns no Comment data, just the User columns. For this reason, joins is used less commonly than includes.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What are the CRUD methods for Active Record?

A

Created, Update, Delete

  • delete_all
  • destroy
  • destory_all
  • create!
  • update_attributes
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What does this expression mean: Queries are lazy?

A

Querying methods like group, having, includes, joins, select and where return an object of type ActiveRecord::Relation. The Relation object looks a lot like an Array; like an Array you can iterate through it or index into it.

There is one major difference from an Array: the contents of Relation are not fetched until needed. This is called laziness. The Relation is not evaluated (a database query is not fired) until the results are needed.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What is ActiveRecord::Relation?

A

Querying methods like group, having, includes, joins, select and where return an object of type ActiveRecord::Relation. The Relation object looks a lot like an Array; like an Array you can iterate through it or index into it.

There is one major difference from an Array: the contents of Relation are not fetched until needed

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

How are query results cached by the Relation object?

A

After the query is run, the results are cached by Relation; they are stored for later re-use. Subsequent calls to each will not fire a query; they will instead use the prior result. This is an advantage because we can re-use the result without constantly hitting the database over-and-over.

This can sometimes result in unexpected behavior. First, note that when accessing a relation (e.g. user1.posts), a Relation object is returned. The relation is itself cached inside model object (e.g. user1) so that future invocations of the association will not hit the DB.

Caching results makes sense: it saves DB queries. But why is laziness a good thing?

Laziness allows us to build complex queries.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

How do we force an associate to be reloaded?

A

caling variable.tablename(true)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How do we throw away all cached association relations?

A

variable.reload.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Why is laziness a good thing and how does it stack queries?

A

Caching results makes sense: it saves DB queries. But why is laziness a good thing?

Laziness allows us to build complex queries

georges = User.where('first_name = ?', 'George')
georges.where_values
# => ["first_name = 'George'"]
george_harrisons = georges.where('last_name = ?', 'Harrison')
george_harrisons.where_values
# => ["first_name = 'George'", "last_name = 'Harrison'"]

p george_harrisons
In this somewhat silly example, we call where twice. The first call to where returns a Relation which knows to filter by first_name (the condition is stored in the where_values attribute). Next, we call where on this Relation; this produces a new Relation object which will know to filter by both first_name and last_name (you can see that where_values was extended).

Note that the additional where created a new Relation; the original georges is not changed.

The first Relation returned by the first where is never evaluated. Instead, we build a second Relation from it. Here laziness helps us; it lets us build up a query by chaining query methods, none of which are executed until the chain is finished being built and evaluated.

Just like where has a where_values attribute, there are similar accessors for includes_values, joins_values, etc. You won’t ever access the attributes directly, but you can see how Relation builds up the query by storing each of the conditions. When the Relation needs to be evaluated, ActiveRecord looks at each of these values to build the SQL to execute.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

How do we force an evaluation of a Relation

A

If you wish to force the evaluation of a Relation, you may call load. This will force evaluation if it hasn’t been done already. Using to_a will return an actual array.

Some other methods like count also force the evaluation of a query.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What is a scope in Active Record?

A

A scope is just a fancy name for an ActiveRecord::Base class method that constructs all or part of a query and then returns the resulting Relation object. Remember, our models inherit from ApplicationRecord, which, in turn, inherits from ActiveRecord::Base.

Use scopes to keep your query code DRY: move frequently-used queries into a scope. It will also make things much more readable by giving a convenient name of your choosing to the query.

class Post < ApplicationRecord
  def self.by_popularity
    self
      .select('posts.*, COUNT(*) AS comment_count')
      .joins(:comments)
      .group('posts.id')
      .order('comment_count DESC')
  end
end

Because it returns a Relation object and not just the results, we can continue to tack query methods onto it. This makes scopes super flexible.

Another awesome thing about scopes is that you can use them with associations. Through a bit of Rails magic, we can call user.posts.by_popularity

Relation objects know what kind of model objects they should contain. Because of this they will actually assume the class methods (including scopes) that are available on that model class.

17
Q

Dynamic Finders: find

A

::find accepts a single argument: the id of the record you’re looking for.

An important difference to note is that ::find will raise an ActiveRecord::RecordNotFound exception if you search for a nonexistent record,

18
Q

Dynamic Finders: find_by

A

::find_by accepts an options hash, which allows us to specify as many criteria as necessary.

::find_by will simply return nil

19
Q

Aggregations in Active Record

A

.count, .sum, .average, .minimum, .maximum

20
Q

What is find_by_SQL

A

ActiveRecord has its limits; it’s great for reducing boilerplate SQL queries, but after a certain point you should drop down and just use SQL yourself. Be flexible; don’t expect too much from ActiveRecord. Even if you have to drop to SQL for a few monster queries, ActiveRecord has saved you a lot of work on all the easy queries.

The main problem with trying to take ActiveRecord too far is that it can become difficult to understand what kind of query it will generate or how it will do what you ask. The more you ask ActiveRecord to do, the more you have to trust that you express yourself properly, and the more you have to think about whether ActiveRecord will do the right thing. Sometimes simpler is better.

If you’d like to use your own SQL to find records in a table you can use find_by_sql. The find_by_sql method will return an array of objects. For example you could run this query:

Case.find_by_sql(<